Index: pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 402)
+++ pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 408)
@@ -38,6 +38,6 @@
 #define THIS_FILE			"stream.c"
 #define ERRLEVEL			1
-#define TRACE_(expr)			stream_perror expr
-#define TRC_(expr)			PJ_LOG(4,expr)
+#define LOGERR_(expr)			stream_perror expr
+#define TRC_(expr)			PJ_LOG(5,expr)
 
 /**
@@ -107,5 +107,6 @@
     pj_size_t		     rtcp_pkt_size; /**< Size of RTCP packet buf.   */
     char		     rtcp_pkt[512]; /**< RTCP packet buffer.	    */
-    pj_uint32_t		     rtcp_tx_time;  /**< RTCP tx time in timestamp  */
+    pj_uint32_t		     rtcp_last_tx;  /**< RTCP tx time in timestamp  */
+    pj_uint32_t		     rtcp_interval; /**< Interval, in timestamp.    */
     int			     rtcp_addrlen;  /**< Address length.	    */
 
@@ -184,5 +185,5 @@
 					channel->pcm_buf_size, &frame_out);
     if (status != 0) {
-	TRACE_((THIS_FILE, "codec decode() error", status));
+	LOGERR_((port->info.name.ptr, "codec decode() error", status));
 
 	frame->type = PJMEDIA_FRAME_TYPE_NONE;
@@ -192,5 +193,6 @@
     /* Put in sound buffer. */
     if (frame_out.size > frame->size) {
-	PJ_LOG(4,(THIS_FILE, "Sound playout buffer truncated %d bytes", 
+	PJ_LOG(4,(port->info.name.ptr, 
+		  "Sound playout buffer truncated %d bytes", 
 		  frame_out.size - frame->size));
 	frame_out.size = frame->size;
@@ -240,9 +242,10 @@
 
 	if (stream->tx_dtmf_count)
-	    PJ_LOG(5,(THIS_FILE,"Sending DTMF digit id %c", 
+	    PJ_LOG(5,(stream->port.info.name.ptr,
+		      "Sending DTMF digit id %c", 
 		      digitmap[stream->tx_dtmf_buf[0].event]));
 
     } else if (duration == 0) {
-	PJ_LOG(5,(THIS_FILE,"Sending DTMF digit id %c", 
+	PJ_LOG(5,(stream->port.info.name.ptr, "Sending DTMF digit id %c", 
 		  digitmap[digit->event]));
     }
@@ -252,100 +255,29 @@
 }
 
+
 /**
- * rec_callback()
+ * check_tx_rtcp()
  *
- * This callback is called when the mic device has gathered
- * enough audio samples. We will encode the audio samples and
- * send it to remote.
- */
-static pj_status_t put_frame( pjmedia_port *port, 
-			      const pjmedia_frame *frame )
-{
-    pjmedia_stream *stream = port->user_data;
-    pjmedia_channel *channel = stream->enc;
-    pj_status_t status = 0;
-    struct pjmedia_frame frame_out;
-    int ts_len;
-    pj_bool_t has_tx;
-    void *rtphdr;
-    int rtphdrlen;
-    pj_ssize_t sent;
-
-    /* Number of samples in the frame */
-    ts_len = frame->size / 2;
-
-    /* Init frame_out buffer. */
-    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr);
-
-    /* Make compiler happy */
-    frame_out.size = 0;
-
-    /* If we have DTMF digits in the queue, transmit the digits. 
-     * Otherwise encode the PCM buffer.
+ * This function is can be called by either put_frame() or get_frame(),
+ * to transmit periodic RTCP SR/RR report.
+ */
+static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp)
+{
+    /* Note that timestamp may represent local or remote timestamp, 
+     * depending on whether this function is called from put_frame()
+     * or get_frame().
      */
-    if (stream->tx_dtmf_count) {
-
-	has_tx = PJ_TRUE;
-	create_dtmf_payload(stream, &frame_out);
-
-	/* Encapsulate. */
-	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
-					 stream->tx_event_pt, 0, 
-					 frame_out.size, ts_len, 
-					 (const void**)&rtphdr, 
-					 &rtphdrlen);
-
-    } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) {
-	unsigned max_size;
-
-	has_tx = PJ_TRUE;
-	max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr);
-	status = stream->codec->op->encode( stream->codec, frame, 
-					    max_size, 
-					    &frame_out);
-	if (status != 0) {
-	    TRACE_((THIS_FILE, "Codec encode() error", status));
-	    return status;
-	}
-
-	//printf("p"); fflush(stdout);
-
-	/* Encapsulate. */
-	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
-					 channel->pt, 0, 
-					 frame_out.size, ts_len, 
-					 (const void**)&rtphdr, 
-					 &rtphdrlen);
-    } else {
-
-	/* Just update RTP session's timestamp. */
-	has_tx = PJ_FALSE;
-	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
-					 0, 0, 
-					 0, ts_len, 
-					 (const void**)&rtphdr, 
-					 &rtphdrlen);
-
-    }
-
-    if (status != PJ_SUCCESS) {
-	TRACE_((THIS_FILE, "RTP encode_rtp() error", status));
-	return status;
-    }
-
-    /* Check if this is the time to transmit RTCP packet */
-    if (stream->rtcp_tx_time == 0) {
-	unsigned first_interval;
-
-	first_interval = PJMEDIA_RTCP_INTERVAL + (pj_rand() % 2000);
-	stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) +
-			       first_interval* stream->port.info.sample_rate /
-			       1000;
-    } else if (pj_ntohl(channel->rtp.out_hdr.ts) >= stream->rtcp_tx_time) {
+
+
+    if (stream->rtcp_last_tx == 0) {
+	
+	stream->rtcp_last_tx = timestamp;
+
+    } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) {
 	
 	pjmedia_rtcp_pkt *rtcp_pkt;
 	pj_ssize_t size;
-	unsigned interval;
 	int len;
+	pj_status_t status;
 
 	pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len);
@@ -359,13 +291,105 @@
 	    
 	    pj_strerror(status, errmsg, sizeof(errmsg));
-	    PJ_LOG(4,(THIS_FILE, "Error sending RTCP: %s [%d]",
+	    PJ_LOG(4,(port->info.name.ptr, "Error sending RTCP: %s [%d]",
 				 errmsg, status));
 	}
 #endif
 
-	interval = PJMEDIA_RTCP_INTERVAL + (pj_rand() % 500);
-	stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) +
-			       interval * stream->port.info.sample_rate /
-			       1000;
+	stream->rtcp_last_tx = timestamp;
+    }
+
+}
+
+
+/**
+ * put_frame()
+ *
+ * This callback is called by upstream component when it has PCM frame
+ * to transmit. This function encodes the PCM frame, pack it into
+ * RTP packet, and transmit to peer.
+ */
+static pj_status_t put_frame( pjmedia_port *port, 
+			      const pjmedia_frame *frame )
+{
+    pjmedia_stream *stream = port->user_data;
+    pjmedia_channel *channel = stream->enc;
+    pj_status_t status = 0;
+    struct pjmedia_frame frame_out;
+    int ts_len;
+    pj_bool_t has_tx;
+    void *rtphdr;
+    int rtphdrlen;
+    pj_ssize_t sent;
+
+    /* Number of samples in the frame */
+    ts_len = frame->size / 2;
+
+    /* Init frame_out buffer. */
+    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr);
+
+    /* Make compiler happy */
+    frame_out.size = 0;
+
+    /* If we have DTMF digits in the queue, transmit the digits. 
+     * Otherwise encode the PCM buffer.
+     */
+    if (stream->tx_dtmf_count) {
+
+	has_tx = PJ_TRUE;
+	create_dtmf_payload(stream, &frame_out);
+
+	/* Encapsulate. */
+	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
+					 stream->tx_event_pt, 0, 
+					 frame_out.size, ts_len, 
+					 (const void**)&rtphdr, 
+					 &rtphdrlen);
+
+    } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) {
+	unsigned max_size;
+
+	has_tx = PJ_TRUE;
+	max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr);
+	status = stream->codec->op->encode( stream->codec, frame, 
+					    max_size, 
+					    &frame_out);
+	if (status != 0) {
+	    LOGERR_((stream->port.info.name.ptr, 
+		    "Codec encode() error", status));
+	    return status;
+	}
+
+	//printf("p"); fflush(stdout);
+
+	/* Encapsulate. */
+	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
+					 channel->pt, 0, 
+					 frame_out.size, ts_len, 
+					 (const void**)&rtphdr, 
+					 &rtphdrlen);
+    } else {
+
+	/* Just update RTP session's timestamp. */
+	has_tx = PJ_FALSE;
+	status = pjmedia_rtp_encode_rtp( &channel->rtp, 
+					 0, 0, 
+					 0, ts_len, 
+					 (const void**)&rtphdr, 
+					 &rtphdrlen);
+
+    }
+
+    if (status != PJ_SUCCESS) {
+	LOGERR_((stream->port.info.name.ptr, 
+		"RTP encode_rtp() error", status));
+	return status;
+    }
+
+    /* Check if now is the time to transmit RTCP SR/RR report. 
+     * We only do this when stream direction is not "decoding only", because
+     * when it is, check_tx_rtcp() will be handled by get_frame().
+     */
+    if (stream->dir != PJMEDIA_DIR_DECODING) {
+	check_tx_rtcp(stream, pj_ntohl(channel->rtp.out_hdr.ts));
     }
 
@@ -450,13 +474,14 @@
     /* Ignore unknown event. */
     if (event->event > 15) {
-	PJ_LOG(5,(THIS_FILE, "Ignored RTP pkt with bad DTMF event %d",
-    			     event->event));
+	PJ_LOG(5,(stream->port.info.name.ptr, 
+		  "Ignored RTP pkt with bad DTMF event %d",
+    		  event->event));
 	return;
     }
 
     /* New event! */
-    PJ_LOG(5,(THIS_FILE, "Received DTMF digit %c, vol=%d",
-    			 digitmap[event->event],
-    			 (event->e_vol & 0x3F)));
+    PJ_LOG(5,(stream->port.info.name.ptr, "Received DTMF digit %c, vol=%d",
+    	      digitmap[event->event],
+    	      (event->e_vol & 0x3F)));
 
     stream->last_dtmf = event->event;
@@ -517,5 +542,5 @@
 					&hdr, &payload, &payloadlen);
 	if (status != PJ_SUCCESS) {
-	    TRACE_((THIS_FILE, "RTP decode error", status));
+	    LOGERR_((stream->port.info.name.ptr, "RTP decode error", status));
 	    goto read_next_packet;
 	}
@@ -537,15 +562,25 @@
 	 */
 	pjmedia_rtp_session_update(&channel->rtp, hdr, &seq_st);
-	if (seq_st.status.flag.bad) {
-	    TRC_  ((THIS_FILE, 
-		    "RTP session_update error: badpt=%d, dup=%d, outorder=%d, "
-		    "probation=%d, restart=%d", 
+	if (seq_st.status.value) {
+	    TRC_  ((stream->port.info.name.ptr, 
+		    "RTP status: badpt=%d, badssrc=%d, dup=%d, "
+		    "outorder=%d, probation=%d, restart=%d", 
 		    seq_st.status.flag.badpt,
+		    seq_st.status.flag.badssrc,
 		    seq_st.status.flag.dup,
 		    seq_st.status.flag.outorder,
 		    seq_st.status.flag.probation,
 		    seq_st.status.flag.restart));
+
+	    if (seq_st.status.flag.badpt) {
+		PJ_LOG(4,(stream->port.info.name.ptr,
+			  "Bad RTP pt %d (expecting %d)",
+			  hdr->pt, channel->rtp.out_pt));
+	    }
+	}
+
+	/* Skip bad RTP packet */
+	if (seq_st.status.flag.bad)
 	    goto read_next_packet;
-	}
 
 
@@ -564,5 +599,6 @@
 		stream->rtp_src_cnt = 0;
 
-		PJ_LOG(4,(THIS_FILE,"Remote RTP address switched to %s:%d",
+		PJ_LOG(4,(stream->port.info.name.ptr,
+			  "Remote RTP address switched to %s:%d",
 			  pj_inet_ntoa(stream->rtp_src_addr.sin_addr),
 			  pj_ntohs(stream->rtp_src_addr.sin_port)));
@@ -571,14 +607,34 @@
 
 
-	/* Put to jitter buffer. */
+
+	/* Put "good" packet to jitter buffer, or reset the jitter buffer
+	 * when RTP session is restarted.
+	 */
 	pj_mutex_lock( stream->jb_mutex );
-	status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen, 
-					pj_ntohs(hdr->seq));
+	if (seq_st.status.flag.restart) {
+	    status = pjmedia_jbuf_reset(stream->jb);
+	    PJ_LOG(4,(stream->port.info.name.ptr, "Jitter buffer reset"));
+
+	} else {
+	    status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen,
+					    pj_ntohs(hdr->seq));
+	}
 	pj_mutex_unlock( stream->jb_mutex );
 
+
+	/* Check if now is the time to transmit RTCP SR/RR report.
+	 * We only do this when stream direction is "decoding only", 
+	 * because otherwise check_tx_rtcp() will be handled by put_frame()
+	 */
+	if (stream->dir == PJMEDIA_DIR_DECODING) {
+	    check_tx_rtcp(stream, pj_ntohl(hdr->ts));
+	}
+
 	if (status != 0) {
-	    TRACE_((THIS_FILE, "Jitter buffer put() error", status));
+	    LOGERR_((stream->port.info.name.ptr, "Jitter buffer put() error", 
+		    status));
 	    goto read_next_packet;
 	}
+
 
 read_next_packet:
@@ -603,7 +659,8 @@
 
 	pj_strerror(status, errmsg, sizeof(errmsg));
-	PJ_LOG(4,(THIS_FILE, "Error reading RTP packet: %s [status=%d]. "
-			     "RTP stream thread quitting!",
-			     errmsg, status));
+	PJ_LOG(4,(stream->port.info.name.ptr, 
+		  "Error reading RTP packet: %s [status=%d]. "
+		  "RTP stream thread quitting!",
+		  errmsg, status));
     }
 }
@@ -644,6 +701,7 @@
 
 	pj_strerror(status, errmsg, sizeof(errmsg));
-	PJ_LOG(4,(THIS_FILE, "Error reading RTCP packet: %s [status=%d]",
-			     errmsg, status));
+	PJ_LOG(4,(stream->port.info.name.ptr, 
+		  "Error reading RTCP packet: %s [status=%d]",
+		  errmsg, status));
     }
 
@@ -743,6 +801,11 @@
     PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
 
+    /* Init stream/port name */
+    stream->port.info.name.ptr = pj_pool_alloc(pool, 24);
+    pj_ansi_sprintf(stream->port.info.name.ptr,
+		    "strm%p", stream);
+    stream->port.info.name.slen = pj_ansi_strlen(stream->port.info.name.ptr);
+
     /* Init port. */
-    stream->port.info.name = pj_str("stream");
     stream->port.info.signature = ('S'<<3 | 'T'<<2 | 'R'<<1 | 'M');
     stream->port.info.type = PJMEDIA_TYPE_AUDIO;
@@ -768,7 +831,11 @@
     stream->rem_rtcp_addr = stream->rem_rtp_addr;
     stream->rem_rtcp_addr.sin_port = pj_htons(rtcp_port);
-    stream->tx_event_pt = info->tx_event_pt;
-    stream->rx_event_pt = info->rx_event_pt;
+    stream->rtcp_interval = (PJMEDIA_RTCP_INTERVAL + (pj_rand() % 8000)) * 
+			    info->fmt.sample_rate / 1000;
+
+    stream->tx_event_pt = info->tx_event_pt ? info->tx_event_pt : -1;
+    stream->rx_event_pt = info->rx_event_pt ? info->rx_event_pt : -1;
     stream->last_dtmf = -1;
+
 
     /* Create mutex to protect jitter buffer: */
@@ -813,5 +880,6 @@
     /* Init RTCP session: */
 
-    pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate, 
+    pjmedia_rtcp_init(&stream->rtcp, stream->port.info.name.ptr,
+		      info->fmt.sample_rate, 
 		      stream->port.info.samples_per_frame, 
 		      info->ssrc);
@@ -820,5 +888,6 @@
     /* Create jitter buffer: */
 
-    status = pjmedia_jbuf_create(pool, stream->frame_size, 15, 100,
+    status = pjmedia_jbuf_create(pool, &stream->port.info.name,
+				 stream->frame_size, 15, 100,
 				 &stream->jb);
     if (status != PJ_SUCCESS)
@@ -883,4 +952,6 @@
     /* Success! */
     *p_stream = stream;
+
+    PJ_LOG(5,(THIS_FILE, "Stream %s created", stream->port.info.name.ptr));
     return PJ_SUCCESS;
 
@@ -958,7 +1029,7 @@
 	stream->enc->paused = 0;
 	//pjmedia_snd_stream_start(stream->enc->snd_stream);
-	PJ_LOG(4,(THIS_FILE, "Encoder stream started"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream started"));
     } else {
-	PJ_LOG(4,(THIS_FILE, "Encoder stream paused"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream paused"));
     }
 
@@ -966,7 +1037,7 @@
 	stream->dec->paused = 0;
 	//pjmedia_snd_stream_start(stream->dec->snd_stream);
-	PJ_LOG(4,(THIS_FILE, "Decoder stream started"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream started"));
     } else {
-	PJ_LOG(4,(THIS_FILE, "Decoder stream paused"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream paused"));
     }
 
@@ -998,10 +1069,10 @@
     if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
 	stream->enc->paused = 1;
-	PJ_LOG(4,(THIS_FILE, "Encoder stream paused"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream paused"));
     }
 
     if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
 	stream->dec->paused = 1;
-	PJ_LOG(4,(THIS_FILE, "Decoder stream paused"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream paused"));
     }
 
@@ -1020,10 +1091,10 @@
     if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
 	stream->enc->paused = 1;
-	PJ_LOG(4,(THIS_FILE, "Encoder stream resumed"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream resumed"));
     }
 
     if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
 	stream->dec->paused = 1;
-	PJ_LOG(4,(THIS_FILE, "Decoder stream resumed"));
+	PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream resumed"));
     }
 
