Index: pjproject/trunk/pjmedia/src/pjmedia/conference.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/conference.c	(revision 228)
+++ pjproject/trunk/pjmedia/src/pjmedia/conference.c	(revision 229)
@@ -92,4 +92,5 @@
     pj_snd_stream	 *snd_rec;	/**< Sound recorder stream.	    */
     pj_snd_stream	 *snd_player;	/**< Sound player stream.	    */
+    pj_mutex_t		 *mutex;	/**< Conference mutex.		    */
     struct conf_port	**ports;	/**< Array of ports.		    */
     pj_uint16_t		 *uns_buf;	/**< Buf for unsigned conversion    */
@@ -100,4 +101,7 @@
 };
 
+
+/* Extern */
+unsigned char linear2ulaw(int pcm_val);
 
 /* Prototypes */
@@ -261,4 +265,11 @@
     conf->uns_buf = pj_pool_zalloc(pool, samples_per_frame *
 					 sizeof(conf->uns_buf[0]));
+
+    /* Create mutex. */
+    status = pj_mutex_create_simple(pool, "conf", &conf->mutex);
+    if (status != PJ_SUCCESS)
+	return status;
+
+
     /* Done */
 
@@ -365,4 +376,5 @@
     suspend_sound(conf);
     destroy_sound(conf);
+    pj_mutex_destroy(conf->mutex);
 
     return PJ_SUCCESS;
@@ -386,6 +398,9 @@
 		     PJ_EINVAL);
 
+    pj_mutex_lock(conf->mutex);
+
     if (conf->port_cnt >= conf->max_ports) {
 	pj_assert(!"Too many ports");
+	pj_mutex_unlock(conf->mutex);
 	return PJ_ETOOMANY;
     }
@@ -401,6 +416,8 @@
     /* Create port structure. */
     status = create_conf_port(pool, conf, port_name, &conf_port);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pj_mutex_unlock(conf->mutex);
 	return status;
+    }
 
     /* Set the port */
@@ -413,4 +430,6 @@
     /* Done. */
     *p_port = index;
+
+    pj_mutex_unlock(conf->mutex);
 
     return PJ_SUCCESS;
@@ -462,4 +481,6 @@
     PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL);
     PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL);
+
+    pj_mutex_lock(conf->mutex);
 
     src_port = conf->ports[src_slot];
@@ -481,4 +502,6 @@
     }
 
+    pj_mutex_unlock(conf->mutex);
+
     return PJ_SUCCESS;
 }
@@ -501,4 +524,6 @@
     PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL);
     PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL);
+
+    pj_mutex_lock(conf->mutex);
 
     src_port = conf->ports[src_slot];
@@ -522,4 +547,6 @@
     }
 
+    pj_mutex_unlock(conf->mutex);
+
     return PJ_SUCCESS;
 }
@@ -545,5 +572,6 @@
      * device's threads!
      */
-    //suspend_sound(conf);
+
+    pj_mutex_lock(conf->mutex);
 
     conf_port = conf->ports[port];
@@ -578,12 +606,11 @@
     --conf->port_cnt;
 
-    /* Reactivate sound device if there are connections */
-    if (conf->connect_cnt != 0) {
-    	//resume_sound(conf);
-    } else {
+    /* Stop sound if there's no connection. */
+    if (conf->connect_cnt == 0) {
 	destroy_sound(conf);
     }
 
-    pj_thread_sleep(60);
+    pj_mutex_unlock(conf->mutex);
+
     return PJ_SUCCESS;
 }
@@ -659,5 +686,5 @@
     pjmedia_conf *conf = user_data;
     pj_int16_t *output_buf = output;
-    unsigned i, j;
+    unsigned ci, cj, i, j;
     
     PJ_UNUSED_ARG(timestamp);
@@ -666,11 +693,16 @@
     TRACE_(("p"));
 
-    /* Clear all port's tmp buffers. */
-    for (i=0; i<conf->max_ports; ++i) {
+    pj_mutex_lock(conf->mutex);
+
+    /* Zero all port's temporary buffers. */
+    for (i=0, ci=0; i<conf->max_ports && ci < conf->port_cnt; ++i) {
 	struct conf_port *conf_port = conf->ports[i];
 	pj_uint32_t *sum_buf;
 
+	/* Skip empty slot. */
 	if (!conf_port)
 	    continue;
+
+	++ci;
 
 	conf_port->sources = 0;
@@ -681,11 +713,10 @@
     }
 
-    /* Get frames from all ports, and "add" the signal 
+    /* Get frames from all ports, and "mix" the signal 
      * to sum_buf of all listeners of the port.
      */
-    for (i=0; i<conf->max_ports; ++i) {
+    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) {
 	struct conf_port *conf_port = conf->ports[i];
 	pj_int32_t level;
-	pj_bool_t silence;
 
 	/* Skip empty port. */
@@ -693,13 +724,14 @@
 	    continue;
 
+	++ci;
+
 	/* Skip if we're not allowed to receive from this port. */
 	if (conf_port->rx_setting == PJMEDIA_PORT_DISABLE) {
-	    TRACE_(("rxdis:%d ", i));
 	    continue;
 	}
 
 	/* Get frame from this port. 
-	 * If port has rx_buffer (e.g. sound port), then get the frame 
-	 * from the rx_buffer instead.
+	 * For port zero (sound port), get the frame  from the rx_buffer
+	 * instead.
 	 */
 	if (i==0) {
@@ -712,4 +744,15 @@
 	    }
 
+	    /* Skip if this port is muted/disabled. */
+	    if (conf_port->rx_setting != PJMEDIA_PORT_ENABLE) {
+		continue;
+	    }
+
+
+	    /* Skip if no port is listening to the microphone */
+	    if (conf_port->listener_cnt == 0) {
+		continue;
+	    }
+
 	    rx_buf = conf_port->rx_buf[conf_port->rx_read];
 	    for (j=0; j<conf->samples_per_frame; ++j) {
@@ -726,5 +769,5 @@
 	    pjmedia_port_get_frame(conf_port->port, &frame);
 
-	    if (frame.type == PJMEDIA_FRAME_TYPE_NONE)
+	   if (frame.type == PJMEDIA_FRAME_TYPE_NONE)
 		continue;
 	}
@@ -738,22 +781,19 @@
 	    continue;
 
-	/* Do we have signal? */
-	silence = pjmedia_silence_det_detect_silence(conf_port->vad,
-						     output, 
-						     conf->samples_per_frame,
-						     &level);
-
-	/* Skip if we don't have signal. */
-	if (silence) {
-	    TRACE_(("sil:%d ", i));
-	    continue;
-	}
-
-	/* Convert the buffer to unsigned value */
+	/* Get the signal level. */
+	level = pjmedia_calc_avg_signal(output, conf->samples_per_frame);
+
+	/* Convert level to 8bit complement ulaw */
+	level = linear2ulaw(level) ^ 0xff;
+
+	/* Convert the buffer to unsigned 16bit value */
 	for (j=0; j<conf->samples_per_frame; ++j)
 	    conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)output)[j]);
 
 	/* Add the signal to all listeners. */
-	for (j=0; j<conf->max_ports; ++j) {
+	for (j=0, cj=0; 
+	     j<conf->max_ports && cj<(unsigned)conf_port->listener_cnt;
+	     ++j) 
+	{
 	    struct conf_port *listener = conf->ports[j];
 	    pj_uint32_t *sum_buf;
@@ -763,20 +803,25 @@
 		continue;
 
+	    /* Skip if this is not the listener. */
+	    if (!conf_port->listeners[j])
+		continue;
+
+	    ++cj;
+
 	    /* Skip if this listener doesn't want to receive audio */
 	    if (listener->tx_setting != PJMEDIA_PORT_ENABLE)
 		continue;
 
-	    //TRACE_(("mix:%d->%d ", i, j));
-
+	    /* Mix the buffer */
 	    sum_buf = listener->sum_buf;
 	    for (k=0; k<conf->samples_per_frame; ++k)
-		sum_buf[k] += conf->uns_buf[k];
-
-	    listener->sources++;
+		sum_buf[k] += (conf->uns_buf[k] * level);
+
+	    listener->sources += level;
 	}
     }
 
     /* For all ports, calculate avg signal. */
-    for (i=0; i<conf->max_ports; ++i) {
+    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) {
 	struct conf_port *conf_port = conf->ports[i];
 	pjmedia_frame frame;
@@ -785,4 +830,6 @@
 	if (!conf_port)
 	    continue;
+
+	++ci;
 
 	if (conf_port->tx_setting == PJMEDIA_PORT_MUTE) {
@@ -800,12 +847,4 @@
 	}
 
-	//
-	// TODO:
-	//  When there's no source, not transmit the frame, but instead
-	//  transmit a 'silence' frame. This is to allow the 'port' to
-	//  do some processing, such as updating timestamp for RTP session
-	//  or transmit signal when it's in the middle of transmitting DTMF.
-	//
-
 	target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1?
 			conf_port->tx_buf2 : conf_port->tx_buf1);
@@ -813,5 +852,6 @@
 	if (conf_port->sources) {
 	    for (j=0; j<conf->samples_per_frame; ++j) {
-		target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] / conf_port->sources);
+		target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] / 
+					     conf_port->sources);
 	    }
 	}
@@ -821,7 +861,19 @@
 
 	pj_memset(&frame, 0, sizeof(frame));
-	if (conf_port->sources)
-	    frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-	else
+	if (conf_port->sources) {
+
+	    pj_bool_t is_silence = PJ_FALSE;
+
+	    /* Apply silence detection. */
+#if 0
+	    is_silence = pjmedia_silence_det_detect(conf_port->vad,
+						    target_buf,
+						    conf->samples_per_frame,
+						    NULL);
+#endif
+	    frame.type = is_silence ? PJMEDIA_FRAME_TYPE_NONE : 
+				      PJMEDIA_FRAME_TYPE_AUDIO;
+
+	} else
 	    frame.type = PJMEDIA_FRAME_TYPE_NONE;
 
@@ -836,6 +888,13 @@
 
     /* Return sound playback frame. */
-    for (j=0; j<conf->samples_per_frame; ++j)
-	output_buf[j] = conf->ports[0]->cur_tx_buf[j];
+    if (conf->ports[0]->sources) {
+	for (j=0; j<conf->samples_per_frame; ++j)
+	    output_buf[j] = conf->ports[0]->cur_tx_buf[j];
+    } else {
+	for (j=0; j<conf->samples_per_frame; ++j)
+	    output_buf[j] = 0;
+    }
+
+    pj_mutex_unlock(conf->mutex);
 
     return PJ_SUCCESS;
@@ -863,4 +922,12 @@
 	TRACE_(("rxerr "));
     }
+
+    /* Skip if this port is muted/disabled. */
+    if (snd_port->rx_setting != PJMEDIA_PORT_ENABLE)
+	return PJ_SUCCESS;
+
+    /* Skip if no port is listening to the microphone */
+    if (snd_port->listener_cnt == 0)
+	return PJ_SUCCESS;
 
 
