Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2436)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2437)
@@ -265,4 +265,6 @@
  * are byte-aligned although its payload may not be byte-aligned.
  */
+
+#pragma pack(1)
 typedef struct pjmedia_frame_ext {
     pjmedia_frame   base;	    /**< Base frame info */
@@ -274,4 +276,5 @@
      */
 } pjmedia_frame_ext;
+#pragma pack()
 
 /**
@@ -279,4 +282,5 @@
  * pjmedia_frame_ext structure.
  */
+#pragma pack(1)
 typedef struct pjmedia_frame_ext_subframe {
     pj_uint16_t     bitlen;	    /**< Number of bits in the data */
@@ -284,4 +288,6 @@
 } pjmedia_frame_ext_subframe;
 
+#pragma pack()
+
 
 /**
@@ -305,5 +311,5 @@
 	pjmedia_frame_ext_subframe *fsub;
 	fsub = (pjmedia_frame_ext_subframe*) p;
-	p += fsub->bitlen / 8;
+	p += sizeof(fsub->bitlen) + fsub->bitlen / 8;
 	if (fsub->bitlen % 8)
 	    ++p;
@@ -312,6 +318,9 @@
     tmp = bitlen / 8;
     if (bitlen % 8) ++tmp;
+
     pj_memcpy(p, &bitlen, sizeof(bitlen));
-    pj_memcpy(p + sizeof(bitlen), src, tmp);
+    if (tmp)
+	pj_memcpy(p + sizeof(bitlen), src, tmp);
+
     frm->subframe_cnt++;
     frm->samples_cnt = frm->samples_cnt + samples_cnt;
@@ -339,5 +348,5 @@
 	for (i = 0; i < n; ++i) {	
 	    sf = (pjmedia_frame_ext_subframe*) p;
-	    p += sf->bitlen / 8;
+	    p += sizeof(sf->bitlen) + sf->bitlen / 8;
 	    if (sf->bitlen % 8)
 		++p;
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2436)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2437)
@@ -19,6 +19,8 @@
  */
 #include <pjmedia/conference.h>
+#include <pjmedia/alaw_ulaw.h>
 #include <pjmedia/errno.h>
 #include <pjmedia/port.h>
+#include <pjmedia/silencedet.h>
 #include <pjmedia/sound_port.h>
 #include <pjmedia/stream.h>
@@ -42,16 +44,4 @@
 #endif
 
-
-/* REC_FILE macro enables recording of the samples written to the sound
- * device. The file contains RAW PCM data with no header, and has the
- * same settings (clock rate etc) as the conference bridge.
- * This should only be enabled when debugging audio quality *only*.
- */
-//#define REC_FILE    "confrec.pcm"
-#ifdef REC_FILE
-static FILE *fhnd_rec;
-#endif
-
-
 #define THIS_FILE	    "conf_switch.c"
 
@@ -103,4 +93,5 @@
     pj_timestamp	 ts_clock;
     pj_timestamp	 ts_rx;
+    pj_timestamp	 ts_tx;
 
     /* Tx buffer is a temporary buffer to be used when there's mismatch 
@@ -110,21 +101,4 @@
      */
     pj_uint8_t		 tx_buf[BUFFER_SIZE]; /**< Tx buffer.		    */
-
-    /* When the port is not receiving signal from any other ports (e.g. when
-     * no other ports is transmitting to this port), the bridge periodically
-     * transmit NULL frame to the port to keep the port "alive" (for example,
-     * a stream port needs this heart-beat to periodically transmit silence
-     * frame to keep NAT binding alive).
-     *
-     * This NULL frame should be sent to the port at the port's ptime rate.
-     * So if the port's ptime is greater than the bridge's ptime, the bridge
-     * needs to delay the NULL frame until it's the right time to do so.
-     *
-     * This variable keeps track of how many pending NULL samples are being
-     * "held" for this port. Once this value reaches samples_per_frame
-     * value of the port, a NULL frame is sent. The samples value on this
-     * variable is clocked at the port's clock rate.
-     */
-    unsigned		 tx_heart_beat;
 };
 
@@ -477,4 +451,8 @@
     PJ_ASSERT_RETURN(conf->bits_per_sample == strm_port->info.bits_per_sample,
 		     PJMEDIA_ENCBITS);
+
+    /* Port's samples per frame should be equal to or multiplication of 
+     * conference's samples per frame.
+     */
     PJ_ASSERT_RETURN((conf->samples_per_frame %
 		     strm_port->info.samples_per_frame==0) ||
@@ -981,23 +959,27 @@
 }
 
-/* Deliver frm_src to a conference port (via frm_dst), eventually call 
- * port's put_frame() when samples count in the frm_dst are equal to 
- * port's samples_per_frame.
- */
-static pj_status_t deliver_frame(struct conf_port *cport_dst,
-			         pjmedia_frame *frm_dst,
-			         const pjmedia_frame *frm_src)
-{
+/* Deliver frm_src to a listener port, eventually call  port's put_frame() 
+ * when samples count in the frm_dst are equal to port's samples_per_frame.
+ */
+static pj_status_t write_frame(struct conf_port *cport_dst,
+			       const pjmedia_frame *frm_src)
+{
+    pjmedia_frame *frm_dst = (pjmedia_frame*)cport_dst->tx_buf;
+    
     PJ_TODO(MAKE_SURE_DEST_FRAME_HAS_ENOUGH_SPACE);
 
+    frm_dst->type = frm_src->type;
+    frm_dst->timestamp = cport_dst->ts_tx;
+
     if (frm_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+
 	pjmedia_frame_ext *f_src = (pjmedia_frame_ext*)frm_src;
 	pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst;
 	unsigned i;
 
-	/* Copy frame to listener's TX buffer. */
 	for (i = 0; i < f_src->subframe_cnt; ++i) {
 	    pjmedia_frame_ext_subframe *sf;
 	    
+	    /* Copy frame to listener's TX buffer. */
 	    sf = pjmedia_frame_ext_get_subframe(f_src, i);
 	    pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen, 
@@ -1011,7 +993,11 @@
 	    if (f_dst->samples_cnt == cport_dst->samples_per_frame)
 	    {
-		f_dst->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
 		if (cport_dst->port) {
-		    pjmedia_port_put_frame(cport_dst->port, (pjmedia_frame*)f_dst);
+		    pjmedia_port_put_frame(cport_dst->port, 
+					   (pjmedia_frame*)f_dst);
+
+		    /* Update TX timestamp. */
+		    pj_add_timestamp32(&cport_dst->ts_tx, 
+				       cport_dst->samples_per_frame);
 
 		    /* Reset TX buffer. */
@@ -1022,7 +1008,6 @@
 	}
 
-    } else {
-
-	pjmedia_frame *f_dst = (pjmedia_frame*)frm_dst;
+    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
+
 	pj_int16_t *f_start, *f_end;
 
@@ -1032,12 +1017,13 @@
 	    unsigned nsamples_to_copy, nsamples_req;
 
+	    /* Copy frame to listener's TX buffer. */
 	    nsamples_to_copy = f_end - f_start;
-	    nsamples_req = cport_dst->samples_per_frame - (f_dst->size >> 1);
+	    nsamples_req = cport_dst->samples_per_frame - (frm_dst->size>>1);
 	    if (nsamples_to_copy > nsamples_req)
 		nsamples_to_copy = nsamples_req;
-	    pjmedia_copy_samples((pj_int16_t*)f_dst->buf + (f_dst->size >> 1), 
+	    pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1),
 				 f_start, 
 				 nsamples_to_copy);
-	    f_dst->size += nsamples_to_copy << 1;
+	    frm_dst->size += nsamples_to_copy << 1;
 	    f_start += nsamples_to_copy;
 
@@ -1046,16 +1032,77 @@
 	     * samples per frame.
 	     */
-	    if ((f_dst->size >> 1) == cport_dst->samples_per_frame)
+	    if ((frm_dst->size >> 1) == cport_dst->samples_per_frame)
 	    {
-		f_dst->type = PJMEDIA_FRAME_TYPE_AUDIO;
 		if (cport_dst->port) {
-		    pjmedia_port_put_frame(cport_dst->port, f_dst);
+		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
+
+		    /* Update TX timestamp. */
+		    pj_add_timestamp32(&cport_dst->ts_tx, 
+				       cport_dst->samples_per_frame);
 		 
 		    /* Reset TX buffer. */
-		    f_dst->size = 0;
+		    frm_dst->size = 0;
 		}
 	    }
 	}
 
+    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_NONE) {
+
+	/* Check port format. */
+	if (cport_dst->port && (cport_dst->port->info.format.u32==0 ||
+	    cport_dst->port->info.format.u32 == PJMEDIA_FOURCC_L16))
+	{
+	    /* When there is already some samples in listener's TX buffer, 
+	     * pad the buffer with "zero samples".
+	     */
+	    if (frm_dst->size != 0) {
+		pjmedia_zero_samples((pj_int16_t*)frm_dst->buf,
+				     cport_dst->samples_per_frame - 
+				     (frm_dst->size>>1));
+
+		frm_dst->type = PJMEDIA_FRAME_TYPE_AUDIO;
+		frm_dst->size = cport_dst->samples_per_frame << 1;
+		if (cport_dst->port)
+		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
+
+		/* Update TX timestamp. */
+		pj_add_timestamp32(&cport_dst->ts_tx, 
+				   cport_dst->samples_per_frame);
+
+		/* Reset TX buffer. */
+		frm_dst->size = 0;
+	    }
+	} else {
+	    pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst;
+
+	    if (f_dst->samples_cnt != 0) {
+		frm_dst->type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		pjmedia_frame_ext_append_subframe(f_dst, NULL, 0, (pj_uint16_t)
+						  (cport_dst->samples_per_frame-
+						  f_dst->samples_cnt));
+		if (cport_dst->port)
+		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
+
+		/* Update TX timestamp. */
+		pj_add_timestamp32(&cport_dst->ts_tx, 
+				   cport_dst->samples_per_frame);
+
+		/* Reset TX buffer. */
+		f_dst->subframe_cnt = 0;
+		f_dst->samples_cnt = 0;
+	    }
+	}
+
+	/* Synchronize clock. */
+	while (pj_cmp_timestamp(&cport_dst->ts_clock, 
+				&cport_dst->ts_tx) >= 0)
+	{
+	    if (cport_dst->port) {
+		frm_dst->type = PJMEDIA_FRAME_TYPE_NONE;
+		frm_dst->timestamp = cport_dst->ts_tx;
+		pjmedia_port_put_frame(cport_dst->port, frm_dst);
+	    }
+	    pj_add_timestamp32(&cport_dst->ts_tx, cport_dst->samples_per_frame);
+	}
     }
 
@@ -1072,7 +1119,5 @@
     unsigned ci, i;
     
-    PJ_TODO(ADJUST_AND_CALC_RX_TX_LEVEL_FOR_PCM_FRAMES);
-
-    TRACE_((THIS_FILE, "- clock -"));
+    PJ_TODO(ADJUST_RX_TX_LEVEL_FOR_PCM_FRAMES);
 
     /* Must lock mutex */
@@ -1094,25 +1139,26 @@
 	++ci;
 
-	/* Skip if we're not allowed to receive from this port. */
-	if (cport->rx_setting == PJMEDIA_PORT_DISABLE) {
+	/* Update clock of the port. */
+	pj_add_timestamp32(&cport->ts_clock, conf->samples_per_frame);
+
+	/* Skip if we're not allowed to receive from this port or 
+	 * the port doesn't have listeners.
+	 */
+	if (cport->rx_setting == PJMEDIA_PORT_DISABLE || 
+	    cport->listener_cnt == 0)
+	{
 	    cport->rx_level = 0;
 	    continue;
 	}
 
-	/* Also skip if this port doesn't have listeners. */
-	if (cport->listener_cnt == 0) {
-	    cport->rx_level = 0;
-	    continue;
-	}
-
-	pj_add_timestamp32(&cport->ts_clock, conf->samples_per_frame);
-
-	/* This loop will make sure the ptime between port & conf port 
-	 * are synchronized.
+	/* Get frame from each port, put it to the listener TX buffer,
+	 * and eventually call put_frame() of the listener. This loop 
+	 * will also make sure the ptime between conf & port synchronized.
 	 */
 	while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_rx) > 0) {
-	    pjmedia_frame *f = (pjmedia_frame*) conf->buf;
+	    pjmedia_frame *f = (pjmedia_frame*)conf->buf;
 	    pj_status_t status;
 	    unsigned j;
+	    pj_int32_t level;
 
 	    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
@@ -1126,15 +1172,17 @@
 		continue;
 
-	    if (f->type == PJMEDIA_FRAME_TYPE_NONE) {
-		if (cport->port->info.format.u32 == PJMEDIA_FOURCC_L16) {
-		    pjmedia_zero_samples((pj_int16_t*)f->buf,
-					 cport->samples_per_frame);
-		    f->size = cport->samples_per_frame << 1;
-		    f->type = PJMEDIA_FRAME_TYPE_AUDIO;
-		} else {
-		    /* Handle DTX */
-		    PJ_TODO(HANDLE_DTX);
-		}
+	    /* Calculate RX level. */
+	    if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
+		level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
+						f->size >>1 );
+	    } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+		/* For extended frame, TX level is unknown, so we just set 
+		 * it to NORMAL_LEVEL. 
+		 */
+		level = NORMAL_LEVEL;
+	    } else { /* PJMEDIA_FRAME_TYPE_NONE */
+		level = 0;
 	    }
+	    cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
 
 	    /* Put the frame to all listeners. */
@@ -1142,26 +1190,123 @@
 	    {
 		struct conf_port *listener;
-		pjmedia_frame *frm_dst;
 
 		listener = conf->ports[cport->listener_slots[j]];
 
 		/* Skip if this listener doesn't want to receive audio */
-		if (listener->tx_setting != PJMEDIA_PORT_ENABLE)
+		if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
+		    pj_add_timestamp32(&listener->ts_tx, 
+				       listener->samples_per_frame);
+		    listener->tx_level = 0;
 		    continue;
+		}
     	    
-		if (listener->port)
-		    frm_dst = frame;
-		else
-		    frm_dst = (pjmedia_frame*)listener->tx_buf;
-
-		status = deliver_frame(listener, frm_dst, f);
-		if (status != PJ_SUCCESS)
+		status = write_frame(listener, f);
+		if (status != PJ_SUCCESS) {
+		    listener->tx_level = 0;
 		    continue;
+		}
+
+		/* Set listener TX level equal to transmitter RX level. */
+		listener->tx_level = cport->rx_level;
 	    }
 	}
-	
-	/* Keep alive mechanism. */
-	PJ_TODO(SEND_KEEP_ALIVE_WHEN_NEEDED);
-    }
+    }
+
+    /* Keep alive. Update TX timestamp and send frame type NONE to all 
+     * underflow ports at their own clock.
+     */
+    for (i=1, ci=1; i<conf->max_ports && ci<conf->port_cnt; ++i) {
+	struct conf_port *cport = conf->ports[i];
+
+	/* Skip empty port. */
+	if (!cport)
+	    continue;
+
+	/* Var "ci" is to count how many ports have been visited so far. */
+	++ci;
+
+	if (cport->tx_setting==PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0)
+	{
+	    /* Clear left-over samples in tx_buffer, if any, so that it won't
+	     * be transmitted next time we have audio signal.
+	     */
+	    pj_bzero(cport->tx_buf, sizeof(pjmedia_frame_ext));
+	    
+	    cport->tx_level = 0;
+
+	    while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_tx) >= 0)
+	    {
+		if (cport->tx_setting == PJMEDIA_PORT_ENABLE) {
+		    pjmedia_frame tmp_f;
+
+		    tmp_f.timestamp = cport->ts_tx;
+		    tmp_f.type = PJMEDIA_FRAME_TYPE_NONE;
+		    tmp_f.buf = NULL;
+		    tmp_f.size = 0;
+
+		    pjmedia_port_put_frame(cport->port, &tmp_f);
+		    pj_add_timestamp32(&cport->ts_tx, cport->samples_per_frame);
+		}
+	    }
+	}
+    }
+
+    /* Return sound playback frame. */
+    do {
+	struct conf_port *this_cport = conf->ports[this_port->port_data.ldata];
+	pjmedia_frame *f_src = (pjmedia_frame*) this_cport->tx_buf;
+
+	frame->type = f_src->type;
+
+	if (f_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+	    pjmedia_frame_ext *f_src_ = (pjmedia_frame_ext*)f_src;
+	    pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frame;
+	    pjmedia_frame_ext_subframe *sf;
+	    pj_uint16_t samples_per_subframe;
+	    
+	    f_dst->samples_cnt = 0;
+	    f_dst->subframe_cnt = 0;
+	    i = 0;
+	    samples_per_subframe = f_src_->samples_cnt / f_src_->subframe_cnt;
+
+	    while (f_dst->samples_cnt < this_cport->samples_per_frame) {
+		sf = pjmedia_frame_ext_get_subframe(f_src_, i++);
+		pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen,
+						  samples_per_subframe);
+	    }
+
+	    /* Shift left TX buffer. */
+	    sf = pjmedia_frame_ext_get_subframe(f_src_, i);
+	    if (sf) {
+		pjmedia_frame_ext_subframe *sf_end;
+		unsigned len;
+
+		sf_end = pjmedia_frame_ext_get_subframe(f_src_, 
+						    f_src_->subframe_cnt -1);
+		len = (pj_uint8_t*)sf_end - (pj_uint8_t*)sf + sf_end->bitlen/8;
+		if (sf_end->bitlen % 8 != 0)
+		    ++len;
+		pj_memmove(this_cport->tx_buf + sizeof(pjmedia_frame_ext), sf,
+			   len);
+	    }
+	    f_src_->samples_cnt = f_src_->samples_cnt - 
+				  (pj_uint16_t)(i * samples_per_subframe);
+	    f_src_->subframe_cnt = f_src_->subframe_cnt - (pj_uint16_t)i;
+
+	} else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
+	    pjmedia_copy_samples((pj_int16_t*)frame->buf, 
+				 (pj_int16_t*)f_src->buf, 
+				 this_cport->samples_per_frame);
+	    frame->size = this_cport->samples_per_frame << 1;
+
+	    /* Shift left TX buffer. */
+	    f_src->size -= frame->size;
+	    if (f_src->size)
+		pjmedia_move_samples((pj_int16_t*)f_src->buf,
+				     (pj_int16_t*)f_src->buf + 
+				     this_cport->samples_per_frame,
+				     f_src->size >> 1);
+	}
+    } while (0);
 
     /* Unlock mutex */
@@ -1175,62 +1320,76 @@
  */
 static pj_status_t put_frame(pjmedia_port *this_port, 
-			     const pjmedia_frame *frame)
+			     const pjmedia_frame *f)
 {
     pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
-    struct conf_port *port = conf->ports[this_port->port_data.ldata];
+    struct conf_port *cport = conf->ports[this_port->port_data.ldata];
     unsigned j;
+    pj_int32_t level;
 
     /* Check for correct size. */
-    PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame *
-				     conf->bits_per_sample / 8,
+    PJ_ASSERT_RETURN( f->size == conf->samples_per_frame *
+				 conf->bits_per_sample / 8,
 		      PJMEDIA_ENCSAMPLESPFRAME);
 
+    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
+    
     /* Skip if this port is muted/disabled. */
-    if (port->rx_setting != PJMEDIA_PORT_ENABLE) {
+    if (cport->rx_setting == PJMEDIA_PORT_DISABLE) {
+	cport->rx_level = 0;
 	return PJ_SUCCESS;
     }
 
     /* Skip if no port is listening to the microphone */
-    if (port->listener_cnt == 0) {
+    if (cport->listener_cnt == 0) {
+	cport->rx_level = 0;
 	return PJ_SUCCESS;
     }
 
-    if (frame->type == PJMEDIA_FRAME_TYPE_NONE) {
-	if (this_port->info.format.u32 == PJMEDIA_FOURCC_L16) {
-	    pjmedia_frame *f = (pjmedia_frame*)port->tx_buf;
-
-	    pjmedia_zero_samples((pj_int16_t*)f->buf,
-				 port->samples_per_frame);
-	    f->size = port->samples_per_frame << 1;
-	    f->type = PJMEDIA_FRAME_TYPE_AUDIO;
-	    frame = f;
-	} else {
-	    /* Handle DTX */
-	    PJ_TODO(HANDLE_DTX);
-	}
-    }
+    /* Calculate RX level. */
+    if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) {
+	level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf,
+					f->size >>1 );
+    } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+	/* For extended frame, TX level is unknown, so we just set 
+	 * it to NORMAL_LEVEL. 
+	 */
+	level = NORMAL_LEVEL;
+    } else { /* PJMEDIA_FRAME_TYPE_NONE. */
+	level = 0;
+    }
+    cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff;
 
     /* Put the frame to all listeners. */
-    for (j=0; j < port->listener_cnt; ++j) 
+    for (j=0; j < cport->listener_cnt; ++j) 
     {
 	struct conf_port *listener;
-	pjmedia_frame *frm_dst;
 	pj_status_t status;
 
-	listener = conf->ports[port->listener_slots[j]];
+	listener = conf->ports[cport->listener_slots[j]];
 
 	/* Skip if this listener doesn't want to receive audio */
-	if (listener->tx_setting != PJMEDIA_PORT_ENABLE)
+	if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
+	    pj_add_timestamp32(&listener->ts_tx, 
+			       listener->samples_per_frame);
+	    listener->tx_level = 0;
 	    continue;
+	}
 
 	/* Skip loopback for now. */
-	if (listener == port)
+	if (listener == cport) {
+	    pj_add_timestamp32(&listener->ts_tx, 
+			       listener->samples_per_frame);
+	    listener->tx_level = 0;
 	    continue;
+	}
 	    
-	frm_dst = (pjmedia_frame*)listener->tx_buf;
-
-	status = deliver_frame(listener, frm_dst, frame);
-	if (status != PJ_SUCCESS)
+	status = write_frame(listener, f);
+	if (status != PJ_SUCCESS) {
+	    listener->tx_level = 0;
 	    continue;
+	}
+
+	/* Set listener TX level equal to transmitter RX level. */
+	listener->tx_level = cport->rx_level;
     }
 
