* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/c9/c939e02a5cac09ba9e79df09335ae5af5876fbf4.svn-base b/jni/pjproject-android/.svn/pristine/c9/c939e02a5cac09ba9e79df09335ae5af5876fbf4.svn-base
new file mode 100644
index 0000000..8536f1a
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c939e02a5cac09ba9e79df09335ae5af5876fbf4.svn-base
@@ -0,0 +1,28 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=xapplicationx 4000 RTP/AVP 100
+a=rtpmap:100 myapp/80000
+m=audio 5000 RTP/AVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp",	# response must include SDP
+	   "m=xapplicationx 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+a=crypto"
+	   ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Unknown media and SRTP audio", pjsua_args, sdp, 200,
+			   extra_headers=extra_headers,
+			   resp_inc=include, resp_exc=exclude) 
+
diff --git a/jni/pjproject-android/.svn/pristine/c9/c93da2d890ee5592d99abddb9b1a004341f41cff.svn-base b/jni/pjproject-android/.svn/pristine/c9/c93da2d890ee5592d99abddb9b1a004341f41cff.svn-base
new file mode 100644
index 0000000..eda547c
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c93da2d890ee5592d99abddb9b1a004341f41cff.svn-base
@@ -0,0 +1,58 @@
+
+   /******************************************************************
+
+       iLBC Speech Coder ANSI-C Source Code
+
+       createCB.h
+
+       Copyright (C) The Internet Society (2004).
+       All Rights Reserved.
+
+   ******************************************************************/
+
+   #ifndef __iLBC_CREATECB_H
+   #define __iLBC_CREATECB_H
+
+   void filteredCBvecs(
+       float *cbvectors,   /* (o) Codebook vector for the
+                                  higher section */
+
+
+
+
+
+       float *mem,         /* (i) Buffer to create codebook
+                                  vectors from */
+       int lMem        /* (i) Length of buffer */
+   );
+
+   void searchAugmentedCB(
+       int low,        /* (i) Start index for the search */
+       int high,           /* (i) End index for the search */
+       int stage,          /* (i) Current stage */
+       int startIndex,     /* (i) CB index for the first
+                                  augmented vector */
+       float *target,      /* (i) Target vector for encoding */
+       float *buffer,      /* (i) Pointer to the end of the
+                                  buffer for augmented codebook
+                                  construction */
+       float *max_measure, /* (i/o) Currently maximum measure */
+       int *best_index,/* (o) Currently the best index */
+       float *gain,    /* (o) Currently the best gain */
+       float *energy,      /* (o) Energy of augmented
+                                  codebook vectors */
+       float *invenergy/* (o) Inv energy of aug codebook
+                                  vectors */
+   );
+
+   void createAugmentedVec(
+       int index,          /* (i) Index for the aug vector
+                                  to be created */
+       float *buffer,      /* (i) Pointer to the end of the
+                                  buffer for augmented codebook
+                                  construction */
+       float *cbVec    /* (o) The construced codebook vector */
+   );
+
+   #endif
+
diff --git a/jni/pjproject-android/.svn/pristine/c9/c94550d49dc59aa9a8f60cb6e5610d4d152bf048.svn-base b/jni/pjproject-android/.svn/pristine/c9/c94550d49dc59aa9a8f60cb6e5610d4d152bf048.svn-base
new file mode 100644
index 0000000..b6cc36d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c94550d49dc59aa9a8f60cb6e5610d4d152bf048.svn-base
@@ -0,0 +1,1989 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia/vid_stream.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/event.h>
+#include <pjmedia/rtp.h>
+#include <pjmedia/rtcp.h>
+#include <pjmedia/jbuf.h>
+#include <pjmedia/stream_common.h>
+#include <pj/array.h>
+#include <pj/assert.h>
+#include <pj/compat/socket.h>
+#include <pj/errno.h>
+#include <pj/ioqueue.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/rand.h>
+#include <pj/sock_select.h>
+#include <pj/string.h>	    /* memcpy() */
+
+
+#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
+
+
+#define THIS_FILE			"vid_stream.c"
+#define ERRLEVEL			1
+#define LOGERR_(expr)			stream_perror expr
+#define TRC_(expr)			PJ_LOG(5,expr)
+#define SIGNATURE			PJMEDIA_SIG_PORT_VID_STREAM
+
+#define TRACE_RC			0
+
+/* Tracing jitter buffer operations in a stream session to a CSV file.
+ * The trace will contain JB operation timestamp, frame info, RTP info, and
+ * the JB state right after the operation.
+ */
+#define TRACE_JB			0	/* Enable/disable trace.    */
+#define TRACE_JB_PATH_PREFIX		""	/* Optional path/prefix
+						   for the CSV filename.    */
+#if TRACE_JB
+#   include <pj/file_io.h>
+#   define TRACE_JB_INVALID_FD		((pj_oshandle_t)-1)
+#   define TRACE_JB_OPENED(s)		(s->trace_jb_fd != TRACE_JB_INVALID_FD)
+#endif
+
+#ifndef PJMEDIA_VSTREAM_SIZE
+#   define PJMEDIA_VSTREAM_SIZE	1000
+#endif
+
+#ifndef PJMEDIA_VSTREAM_INC
+#   define PJMEDIA_VSTREAM_INC	1000
+#endif
+
+/* Due to network MTU limitation, a picture bitstream may be splitted into
+ * several chunks for RTP delivery. The chunk number may vary depend on the
+ * picture resolution and MTU. This constant specifies the minimum chunk
+ * number to be allocated to store a picture bitstream in decoding direction.
+ */
+#define MIN_CHUNKS_PER_FRM	30
+
+/* Video stream keep-alive feature is currently disabled. */
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
+#   undef PJMEDIA_STREAM_ENABLE_KA
+#   define PJMEDIA_STREAM_ENABLE_KA 0
+#endif
+
+
+/**
+ * Media channel.
+ */
+typedef struct pjmedia_vid_channel
+{
+    pjmedia_vid_stream	   *stream;	    /**< Parent stream.		    */
+    pjmedia_dir		    dir;	    /**< Channel direction.	    */
+    pjmedia_port	    port;	    /**< Port interface.	    */
+    unsigned		    pt;		    /**< Payload type.		    */
+    pj_bool_t		    paused;	    /**< Paused?.		    */
+    void		   *buf;	    /**< Output buffer.		    */
+    unsigned		    buf_size;	    /**< Size of output buffer.	    */
+    pjmedia_rtp_session	    rtp;	    /**< RTP session.		    */
+} pjmedia_vid_channel;
+
+
+/**
+ * This structure describes media stream.
+ * A media stream is bidirectional media transmission between two endpoints.
+ * It consists of two channels, i.e. encoding and decoding channels.
+ * A media stream corresponds to a single "m=" line in a SDP session
+ * description.
+ */
+struct pjmedia_vid_stream
+{
+    pj_pool_t		    *own_pool;      /**< Internal pool.		    */
+    pjmedia_endpt	    *endpt;	    /**< Media endpoint.	    */
+    pjmedia_vid_codec_mgr   *codec_mgr;	    /**< Codec manager.		    */
+    pjmedia_vid_stream_info  info;	    /**< Stream info.		    */
+
+    pjmedia_vid_channel	    *enc;	    /**< Encoding channel.	    */
+    pjmedia_vid_channel	    *dec;	    /**< Decoding channel.	    */
+
+    pjmedia_dir		     dir;	    /**< Stream direction.	    */
+    void		    *user_data;	    /**< User data.		    */
+    pj_str_t		     name;	    /**< Stream name		    */
+    pj_str_t		     cname;	    /**< SDES CNAME		    */
+
+    pjmedia_transport	    *transport;	    /**< Stream transport.	    */
+    unsigned		     send_err_cnt;  /**< Send error count.          */
+
+    pj_mutex_t		    *jb_mutex;
+    pjmedia_jbuf	    *jb;	    /**< Jitter buffer.		    */
+    char		     jb_last_frm;   /**< Last frame type from jb    */
+    unsigned		     jb_last_frm_cnt;/**< Last JB frame type counter*/
+
+    pjmedia_rtcp_session     rtcp;	    /**< RTCP for incoming RTP.	    */
+    pj_uint32_t		     rtcp_last_tx;  /**< RTCP tx time in timestamp  */
+    pj_uint32_t		     rtcp_interval; /**< Interval, in timestamp.    */
+    pj_bool_t		     initial_rr;    /**< Initial RTCP RR sent	    */
+    pj_bool_t                rtcp_sdes_bye_disabled;/**< Send RTCP SDES/BYE?*/
+    void		    *out_rtcp_pkt;  /**< Outgoing RTCP packet.	    */
+    unsigned		     out_rtcp_pkt_size;
+					    /**< Outgoing RTCP packet size. */
+
+    unsigned		     dec_max_size;  /**< Size of decoded/raw picture*/
+    pjmedia_ratio	     dec_max_fps;   /**< Max fps of decoding dir.   */
+    pjmedia_frame            dec_frame;	    /**< Current decoded frame.     */
+    pjmedia_event            fmt_event;	    /**< Buffered fmt_changed event
+                                                 to avoid deadlock	    */
+    pjmedia_event            miss_keyframe_event; 
+					    /**< Buffered missing keyframe
+                                                 event for delayed republish*/
+
+    unsigned		     frame_size;    /**< Size of encoded base frame.*/
+    unsigned		     frame_ts_len;  /**< Frame length in timestamp. */
+
+    unsigned		     rx_frame_cnt;  /**< # of array in rx_frames    */
+    pjmedia_frame	    *rx_frames;	    /**< Temp. buffer for incoming
+					         frame assembly.	    */
+
+    pj_bool_t		     force_keyframe;/**< Forced to encode keyframe? */
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
+    pj_bool_t		     use_ka;	       /**< Stream keep-alive with non-
+						    codec-VAD mechanism is
+						    enabled?		    */
+    pj_timestamp	     last_frm_ts_sent; /**< Timestamp of last sending
+					            packet		    */
+#endif
+
+#if TRACE_JB
+    pj_oshandle_t	     trace_jb_fd;   /**< Jitter tracing file handle.*/
+    char		    *trace_jb_buf;  /**< Jitter tracing buffer.	    */
+#endif
+
+    pjmedia_vid_codec	    *codec;	    /**< Codec instance being used. */
+    pj_uint32_t		     last_dec_ts;   /**< Last decoded timestamp.    */
+    int			     last_dec_seq;  /**< Last decoded sequence.     */
+
+
+    pj_timestamp	     ts_freq;	    /**< Timestamp frequency.	    */
+
+#if TRACE_RC
+    unsigned		     rc_total_sleep;
+    unsigned		     rc_total_pkt;
+    unsigned		     rc_total_img;
+    pj_timestamp	     tx_start;
+    pj_timestamp	     tx_end;
+#endif
+};
+
+/* Prototypes */
+static pj_status_t decode_frame(pjmedia_vid_stream *stream,
+                                pjmedia_frame *frame);
+
+/*
+ * Print error.
+ */
+static void stream_perror(const char *sender, const char *title,
+			  pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+
+    pj_strerror(status, errmsg, sizeof(errmsg));
+    PJ_LOG(4,(sender, "%s: %s [err:%d]", title, errmsg, status));
+}
+
+
+static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
+			     pj_bool_t with_sdes,
+			     pj_bool_t with_bye);
+
+
+#if TRACE_JB
+
+PJ_INLINE(int) trace_jb_print_timestamp(char **buf, pj_ssize_t len)
+{
+    pj_time_val now;
+    pj_parsed_time ptime;
+    char *p = *buf;
+
+    if (len < 14)
+	return -1;
+
+    pj_gettimeofday(&now);
+    pj_time_decode(&now, &ptime);
+    p += pj_utoa_pad(ptime.hour, p, 2, '0');
+    *p++ = ':';
+    p += pj_utoa_pad(ptime.min, p, 2, '0');
+    *p++ = ':';
+    p += pj_utoa_pad(ptime.sec, p, 2, '0');
+    *p++ = '.';
+    p += pj_utoa_pad(ptime.msec, p, 3, '0');
+    *p++ = ',';
+
+    *buf = p;
+
+    return 0;
+}
+
+PJ_INLINE(int) trace_jb_print_state(pjmedia_vid_stream *stream, 
+				    char **buf, pj_ssize_t len)
+{
+    char *p = *buf;
+    char *endp = *buf + len;
+    pjmedia_jb_state state;
+
+    pjmedia_jbuf_get_state(stream->jb, &state);
+
+    len = pj_ansi_snprintf(p, endp-p, "%d, %d, %d",
+			   state.size, state.burst, state.prefetch);
+    if ((len < 0) || (len >= endp-p))
+	return -1;
+
+    p += len;
+    *buf = p;
+    return 0;
+}
+
+static void trace_jb_get(pjmedia_vid_stream *stream, pjmedia_jb_frame_type ft,
+			 pj_size_t fsize)
+{
+    char *p = stream->trace_jb_buf;
+    char *endp = stream->trace_jb_buf + PJ_LOG_MAX_SIZE;
+    pj_ssize_t len = 0;
+    const char* ft_st;
+
+    if (!TRACE_JB_OPENED(stream))
+	return;
+
+    /* Print timestamp. */
+    if (trace_jb_print_timestamp(&p, endp-p))
+	goto on_insuff_buffer;
+
+    /* Print frame type and size */
+    switch(ft) {
+	case PJMEDIA_JB_MISSING_FRAME:
+	    ft_st = "missing";
+	    break;
+	case PJMEDIA_JB_NORMAL_FRAME:
+	    ft_st = "normal";
+	    break;
+	case PJMEDIA_JB_ZERO_PREFETCH_FRAME:
+	    ft_st = "prefetch";
+	    break;
+	case PJMEDIA_JB_ZERO_EMPTY_FRAME:
+	    ft_st = "empty";
+	    break;
+	default:
+	    ft_st = "unknown";
+	    break;
+    }
+
+    /* Print operation, size, frame count, frame type */
+    len = pj_ansi_snprintf(p, endp-p, "GET,%d,1,%s,,,,", fsize, ft_st);
+    if ((len < 0) || (len >= endp-p))
+	goto on_insuff_buffer;
+    p += len;
+
+    /* Print JB state */
+    if (trace_jb_print_state(stream, &p, endp-p))
+	goto on_insuff_buffer;
+
+    /* Print end of line */
+    if (endp-p < 2)
+	goto on_insuff_buffer;
+    *p++ = '\n';
+
+    /* Write and flush */
+    len = p - stream->trace_jb_buf;
+    pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
+    pj_file_flush(stream->trace_jb_fd);
+    return;
+
+on_insuff_buffer:
+    pj_assert(!"Trace buffer too small, check PJ_LOG_MAX_SIZE!");
+}
+
+static void trace_jb_put(pjmedia_vid_stream *stream,
+			 const pjmedia_rtp_hdr *hdr,
+			 unsigned payloadlen, unsigned frame_cnt)
+{
+    char *p = stream->trace_jb_buf;
+    char *endp = stream->trace_jb_buf + PJ_LOG_MAX_SIZE;
+    pj_ssize_t len = 0;
+
+    if (!TRACE_JB_OPENED(stream))
+	return;
+
+    /* Print timestamp. */
+    if (trace_jb_print_timestamp(&p, endp-p))
+	goto on_insuff_buffer;
+
+    /* Print operation, size, frame count, RTP info */
+    len = pj_ansi_snprintf(p, endp-p,
+			   "PUT,%d,%d,,%d,%d,%d,",
+			   payloadlen, frame_cnt,
+			   pj_ntohs(hdr->seq), pj_ntohl(hdr->ts), hdr->m);
+    if ((len < 0) || (len >= endp-p))
+	goto on_insuff_buffer;
+    p += len;
+
+    /* Print JB state */
+    if (trace_jb_print_state(stream, &p, endp-p))
+	goto on_insuff_buffer;
+
+    /* Print end of line */
+    if (endp-p < 2)
+	goto on_insuff_buffer;
+    *p++ = '\n';
+
+    /* Write and flush */
+    len = p - stream->trace_jb_buf;
+    pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
+    pj_file_flush(stream->trace_jb_fd);
+    return;
+
+on_insuff_buffer:
+    pj_assert(!"Trace buffer too small, check PJ_LOG_MAX_SIZE!");
+}
+
+#endif /* TRACE_JB */
+
+static void dump_port_info(const pjmedia_vid_channel *chan,
+                           const char *event_name)
+{
+    const pjmedia_port_info *pi = &chan->port.info;
+    char fourcc_name[5];
+
+    PJ_LOG(5, (pi->name.ptr,
+	       " %s format %s: %dx%d %s%s %d/%d(~%d)fps",
+	       (chan->dir==PJMEDIA_DIR_DECODING? "Decoding":"Encoding"),
+	       event_name,
+	       pi->fmt.det.vid.size.w, pi->fmt.det.vid.size.h,
+	       pjmedia_fourcc_name(pi->fmt.id, fourcc_name),
+	       (chan->dir==PJMEDIA_DIR_ENCODING?"->":"<-"),
+	       pi->fmt.det.vid.fps.num, pi->fmt.det.vid.fps.denum,
+	       pi->fmt.det.vid.fps.num/pi->fmt.det.vid.fps.denum));
+}
+
+/*
+ * Handle events from stream components.
+ */
+static pj_status_t stream_event_cb(pjmedia_event *event,
+                                   void *user_data)
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*)user_data;
+
+    if (event->epub == stream->codec) {
+	/* This is codec event */
+	switch (event->type) {
+	case PJMEDIA_EVENT_FMT_CHANGED:
+	    /* Copy the event to avoid deadlock if we publish the event
+	     * now. This happens because fmt_event may trigger restart
+	     * while we're still holding the jb_mutex.
+	     */
+	    pj_memcpy(&stream->fmt_event, event, sizeof(*event));
+	    return PJ_SUCCESS;
+
+	case PJMEDIA_EVENT_KEYFRAME_MISSING:
+	    /* Republish this event later from get_frame(). */
+	    pj_memcpy(&stream->miss_keyframe_event, event, sizeof(*event));
+	    return PJ_SUCCESS;
+
+	default:
+	    break;
+	}
+    }
+
+    return pjmedia_event_publish(NULL, stream, event, 0);
+}
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
+/*
+ * Send keep-alive packet using non-codec frame.
+ */
+static void send_keep_alive_packet(pjmedia_vid_stream *stream)
+{
+#if PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_EMPTY_RTP
+
+    /* Keep-alive packet is empty RTP */
+    pjmedia_vid_channel *channel = stream->enc;
+    pj_status_t status;
+    void *pkt;
+    int pkt_len;
+
+    TRC_((channel->port.info.name.ptr,
+	  "Sending keep-alive (RTCP and empty RTP)"));
+
+    /* Send RTP */
+    status = pjmedia_rtp_encode_rtp( &stream->enc->rtp,
+				     stream->enc->pt, 0,
+				     1,
+				     0,
+				     (const void**)&pkt,
+				     &pkt_len);
+    pj_assert(status == PJ_SUCCESS);
+
+    pj_memcpy(stream->enc->buf, pkt, pkt_len);
+    pjmedia_transport_send_rtp(stream->transport, stream->enc->buf,
+			       pkt_len);
+
+    /* Send RTCP */
+    send_rtcp(stream, PJ_TRUE, PJ_FALSE);
+
+#elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER
+
+    /* Keep-alive packet is defined in PJMEDIA_STREAM_KA_USER_PKT */
+    pjmedia_vid_channel *channel = stream->enc;
+    int pkt_len;
+    const pj_str_t str_ka = PJMEDIA_STREAM_KA_USER_PKT;
+
+    TRC_((channel->port.info.name.ptr,
+	  "Sending keep-alive (custom RTP/RTCP packets)"));
+
+    /* Send to RTP port */
+    pj_memcpy(stream->enc->buf, str_ka.ptr, str_ka.slen);
+    pkt_len = str_ka.slen;
+    pjmedia_transport_send_rtp(stream->transport, stream->enc->buf,
+			       pkt_len);
+
+    /* Send to RTCP port */
+    pjmedia_transport_send_rtcp(stream->transport, stream->enc->buf,
+			        pkt_len);
+
+#else
+    
+    PJ_UNUSED_ARG(stream);
+
+#endif
+}
+#endif	/* defined(PJMEDIA_STREAM_ENABLE_KA) */
+
+
+static pj_status_t send_rtcp(pjmedia_vid_stream *stream,
+			     pj_bool_t with_sdes,
+			     pj_bool_t with_bye)
+{
+    void *sr_rr_pkt;
+    pj_uint8_t *pkt;
+    int len, max_len;
+    pj_status_t status;
+
+    /* Build RTCP RR/SR packet */
+    pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len);
+
+    if (with_sdes || with_bye) {
+	pkt = (pj_uint8_t*) stream->out_rtcp_pkt;
+	pj_memcpy(pkt, sr_rr_pkt, len);
+	max_len = stream->out_rtcp_pkt_size;
+    } else {
+	pkt = (pj_uint8_t*)sr_rr_pkt;
+	max_len = len;
+    }
+
+    /* Build RTCP SDES packet */
+    if (with_sdes) {
+	pjmedia_rtcp_sdes sdes;
+	pj_size_t sdes_len;
+
+	pj_bzero(&sdes, sizeof(sdes));
+	sdes.cname = stream->cname;
+	sdes_len = max_len - len;
+	status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len,
+					      &sdes_len, &sdes);
+	if (status != PJ_SUCCESS) {
+	    PJ_PERROR(4,(stream->name.ptr, status,
+        			     "Error generating RTCP SDES"));
+	} else {
+	    len += (int)sdes_len;
+	}
+    }
+
+    /* Build RTCP BYE packet */
+    if (with_bye) {
+	pj_size_t bye_len;
+
+	bye_len = max_len - len;
+	status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len,
+					     &bye_len, NULL);
+	if (status != PJ_SUCCESS) {
+	    PJ_PERROR(4,(stream->name.ptr, status,
+        			     "Error generating RTCP BYE"));
+	} else {
+	    len += (int)bye_len;
+	}
+    }
+
+    /* Send! */
+    status = pjmedia_transport_send_rtcp(stream->transport, pkt, len);
+
+    return status;
+}
+
+
+/**
+ * check_tx_rtcp()
+ *
+ * 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_vid_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->rtcp_last_tx == 0) {
+	
+	stream->rtcp_last_tx = timestamp;
+
+    } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) {
+	pj_status_t status;
+	
+	status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE);
+	if (status != PJ_SUCCESS) {
+	    PJ_PERROR(4,(stream->name.ptr, status,
+        		 "Error sending RTCP"));
+	}
+
+	stream->rtcp_last_tx = timestamp;
+    }
+}
+
+
+#if 0
+static void dump_bin(const char *buf, unsigned len)
+{
+    unsigned i;
+
+    PJ_LOG(3,(THIS_FILE, "begin dump"));
+    for (i=0; i<len; ++i) {
+	int j;
+	char bits[9];
+	unsigned val = buf[i] & 0xFF;
+
+	bits[8] = '\0';
+	for (j=0; j<8; ++j) {
+	    if (val & (1 << (7-j)))
+		bits[j] = '1';
+	    else
+		bits[j] = '0';
+	}
+
+	PJ_LOG(3,(THIS_FILE, "%2d %s [%d]", i, bits, val));
+    }
+    PJ_LOG(3,(THIS_FILE, "end dump"));
+}
+#endif
+
+
+/*
+ * This callback is called by stream transport on receipt of packets
+ * in the RTP socket. 
+ */
+static void on_rx_rtp( void *data, 
+		       void *pkt,
+                       pj_ssize_t bytes_read)
+
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) data;
+    pjmedia_vid_channel *channel = stream->dec;
+    const pjmedia_rtp_hdr *hdr;
+    const void *payload;
+    unsigned payloadlen;
+    pjmedia_rtp_status seq_st;
+    pj_status_t status;
+    pj_bool_t pkt_discarded = PJ_FALSE;
+
+    /* Check for errors */
+    if (bytes_read < 0) {
+	LOGERR_((channel->port.info.name.ptr, "RTP recv() error", 
+		(pj_status_t)-bytes_read));
+	return;
+    }
+
+    /* Ignore keep-alive packets */
+    if (bytes_read < (pj_ssize_t) sizeof(pjmedia_rtp_hdr))
+	return;
+
+    /* Update RTP and RTCP session. */
+    status = pjmedia_rtp_decode_rtp(&channel->rtp, pkt, (int)bytes_read,
+				    &hdr, &payload, &payloadlen);
+    if (status != PJ_SUCCESS) {
+	LOGERR_((channel->port.info.name.ptr, "RTP decode error", status));
+	stream->rtcp.stat.rx.discard++;
+	return;
+    }
+
+    /* Ignore the packet if decoder is paused */
+    if (channel->paused)
+	goto on_return;
+
+    /* Update RTP session (also checks if RTP session can accept
+     * the incoming packet.
+     */
+    pjmedia_rtp_session_update2(&channel->rtp, hdr, &seq_st, PJ_TRUE);
+    if (seq_st.status.value) {
+	TRC_  ((channel->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,(channel->port.info.name.ptr,
+		      "Bad RTP pt %d (expecting %d)",
+		      hdr->pt, channel->rtp.out_pt));
+	}
+
+	if (seq_st.status.flag.badssrc) {
+	    PJ_LOG(4,(channel->port.info.name.ptr,
+		      "Changed RTP peer SSRC %d (previously %d)",
+		      channel->rtp.peer_ssrc, stream->rtcp.peer_ssrc));
+	    stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc;
+	}
+
+
+    }
+
+    /* Skip bad RTP packet */
+    if (seq_st.status.flag.bad) {
+	pkt_discarded = PJ_TRUE;
+	goto on_return;
+    }
+
+    /* Ignore if payloadlen is zero */
+    if (payloadlen == 0) {
+	pkt_discarded = PJ_TRUE;
+	goto on_return;
+    }
+
+    pj_mutex_lock( stream->jb_mutex );
+
+    /* Quickly see if there may be a full picture in the jitter buffer, and
+     * decode them if so. More thorough check will be done in decode_frame().
+     */
+    if ((pj_ntohl(hdr->ts) != stream->dec_frame.timestamp.u32.lo) || hdr->m) {
+	if (PJMEDIA_VID_STREAM_SKIP_PACKETS_TO_REDUCE_LATENCY) {
+	    /* Always decode whenever we have picture in jb and
+	     * overwrite already decoded picture if necessary
+	     */
+	    pj_size_t old_size = stream->dec_frame.size;
+
+	    stream->dec_frame.size = stream->dec_max_size;
+	    if (decode_frame(stream, &stream->dec_frame) != PJ_SUCCESS) {
+		stream->dec_frame.size = old_size;
+	    }
+	} else {
+	    /* Only decode if we don't already have decoded one,
+	     * unless the jb is full.
+	     */
+	    pj_bool_t can_decode = PJ_FALSE;
+
+	    if (pjmedia_jbuf_is_full(stream->jb)) {
+		can_decode = PJ_TRUE;
+	    }
+	    else if (stream->dec_frame.size == 0) {
+		can_decode = PJ_TRUE;
+	    }
+
+	    if (can_decode) {
+		stream->dec_frame.size = stream->dec_max_size;
+		if (decode_frame(stream, &stream->dec_frame) != PJ_SUCCESS) {
+		    stream->dec_frame.size = 0;
+		}
+	    }
+	}
+    }
+
+    /* Put "good" packet to jitter buffer, or reset the jitter buffer
+     * when RTP session is restarted.
+     */
+    if (seq_st.status.flag.restart) {
+	status = pjmedia_jbuf_reset(stream->jb);
+	PJ_LOG(4,(channel->port.info.name.ptr, "Jitter buffer reset"));
+    } else {
+	/* Just put the payload into jitter buffer */
+	pjmedia_jbuf_put_frame3(stream->jb, payload, payloadlen, 0, 
+				pj_ntohs(hdr->seq), pj_ntohl(hdr->ts), NULL);
+
+#if TRACE_JB
+	trace_jb_put(stream, hdr, payloadlen, count);
+#endif
+
+    }
+    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) {
+	LOGERR_((channel->port.info.name.ptr, "Jitter buffer put() error", 
+		status));
+	pkt_discarded = PJ_TRUE;
+	goto on_return;
+    }
+
+on_return:
+    /* Update RTCP session */
+    if (stream->rtcp.peer_ssrc == 0)
+	stream->rtcp.peer_ssrc = channel->rtp.peer_ssrc;
+
+    pjmedia_rtcp_rx_rtp2(&stream->rtcp, pj_ntohs(hdr->seq),
+			 pj_ntohl(hdr->ts), payloadlen, pkt_discarded);
+
+    /* Send RTCP RR and SDES after we receive some RTP packets */
+    if (stream->rtcp.received >= 10 && !stream->initial_rr) {
+	status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled,
+			   PJ_FALSE);
+        if (status != PJ_SUCCESS) {
+            PJ_PERROR(4,(stream->name.ptr, status,
+            	     "Error sending initial RTCP RR"));
+	} else {
+	    stream->initial_rr = PJ_TRUE;
+	}
+    }
+}
+
+
+/*
+ * This callback is called by stream transport on receipt of packets
+ * in the RTCP socket. 
+ */
+static void on_rx_rtcp( void *data,
+                        void *pkt, 
+                        pj_ssize_t bytes_read)
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) data;
+
+    /* Check for errors */
+    if (bytes_read < 0) {
+	LOGERR_((stream->cname.ptr, "RTCP recv() error", 
+		 (pj_status_t)-bytes_read));
+	return;
+    }
+
+    pjmedia_rtcp_rx_rtcp(&stream->rtcp, pkt, bytes_read);
+}
+
+static pj_status_t put_frame(pjmedia_port *port,
+                             pjmedia_frame *frame)
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata;
+    pjmedia_vid_channel *channel = stream->enc;
+    pj_status_t status = 0;
+    pjmedia_frame frame_out;
+    unsigned rtp_ts_len;
+    void *rtphdr;
+    int rtphdrlen;
+    pj_bool_t has_more_data = PJ_FALSE;
+    pj_size_t total_sent = 0;
+    pjmedia_vid_encode_opt enc_opt;
+    unsigned pkt_cnt = 0;
+    pj_timestamp initial_time;
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
+    /* If the interval since last sending packet is greater than
+     * PJMEDIA_STREAM_KA_INTERVAL, send keep-alive packet.
+     */
+    if (stream->use_ka)
+    {
+	pj_uint32_t dtx_duration;
+
+	dtx_duration = pj_timestamp_diff32(&stream->last_frm_ts_sent, 
+					   &frame->timestamp);
+        /* Video stream keep-alive feature is currently disabled. */
+        /*
+        if (dtx_duration >
+	    PJMEDIA_STREAM_KA_INTERVAL *
+            PJMEDIA_PIA_SRATE(&channel->port.info))
+	{
+	    send_keep_alive_packet(stream);
+	    stream->last_frm_ts_sent = frame->timestamp;
+	}
+        */
+    }
+#endif
+
+    /* Don't do anything if stream is paused */
+    if (channel->paused) {
+	return PJ_SUCCESS;
+    }
+
+    /* Get frame length in timestamp unit */
+    rtp_ts_len = stream->frame_ts_len;
+
+    /* Init frame_out buffer. */
+    frame_out.buf = ((char*)channel->buf) + sizeof(pjmedia_rtp_hdr);
+    frame_out.size = 0;
+
+    /* Init encoding option */
+    pj_bzero(&enc_opt, sizeof(enc_opt));
+    if (stream->force_keyframe) {
+	/* Force encoder to generate keyframe */
+	enc_opt.force_keyframe = PJ_TRUE;
+	stream->force_keyframe = PJ_FALSE;
+	TRC_((channel->port.info.name.ptr,
+	      "Forcing encoder to generate keyframe"));
+    }
+
+    /* Encode! */
+    status = pjmedia_vid_codec_encode_begin(stream->codec, &enc_opt, frame,
+                                            channel->buf_size -
+                                               sizeof(pjmedia_rtp_hdr),
+                                            &frame_out,
+                                            &has_more_data);
+    if (status != PJ_SUCCESS) {
+	LOGERR_((channel->port.info.name.ptr,
+		"Codec encode_begin() error", status));
+
+	/* Update RTP timestamp */
+	pjmedia_rtp_encode_rtp(&channel->rtp, channel->pt, 1, 0,
+			       rtp_ts_len,  (const void**)&rtphdr,
+			       &rtphdrlen);
+	return status;
+    }
+    
+    pj_get_timestamp(&initial_time);
+
+    /* Loop while we have frame to send */
+    for (;;) {
+	status = pjmedia_rtp_encode_rtp(&channel->rtp,
+	                                channel->pt,
+	                                (has_more_data == PJ_FALSE ? 1 : 0),
+	                                (int)frame_out.size,
+	                                rtp_ts_len,
+	                                (const void**)&rtphdr,
+	                                &rtphdrlen);
+	if (status != PJ_SUCCESS) {
+	    LOGERR_((channel->port.info.name.ptr,
+		    "RTP encode_rtp() error", status));
+	    return status;
+	}
+
+	// Copy RTP header to the beginning of packet
+	pj_memcpy(channel->buf, rtphdr, sizeof(pjmedia_rtp_hdr));
+
+	// Send the RTP packet to the transport.
+	status = pjmedia_transport_send_rtp(stream->transport,
+	                                    (char*)channel->buf,
+	                                    frame_out.size +
+						sizeof(pjmedia_rtp_hdr));
+	if (status != PJ_SUCCESS) {
+	    enum { COUNT_TO_REPORT = 20 };
+	    if (stream->send_err_cnt++ == 0) {
+		LOGERR_((channel->port.info.name.ptr,
+			 "Transport send_rtp() error",
+			 status));
+	    }
+	    if (stream->send_err_cnt > COUNT_TO_REPORT)
+		stream->send_err_cnt = 0;
+	    /* Ignore this error */
+	}
+
+	pjmedia_rtcp_tx_rtp(&stream->rtcp, (unsigned)frame_out.size);
+	total_sent += frame_out.size;
+	pkt_cnt++;
+
+	if (!has_more_data)
+	    break;
+
+	/* Next packets use same timestamp */
+	rtp_ts_len = 0;
+
+	frame_out.size = 0;
+
+	/* Encode more! */
+	status = pjmedia_vid_codec_encode_more(stream->codec,
+	                                       channel->buf_size -
+						   sizeof(pjmedia_rtp_hdr),
+				               &frame_out,
+					       &has_more_data);
+	if (status != PJ_SUCCESS) {
+	    LOGERR_((channel->port.info.name.ptr,
+		     "Codec encode_more() error", status));
+	    /* Ignore this error (?) */
+	    break;
+	}
+
+	/* Send rate control */
+	if (stream->info.rc_cfg.method==PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING)
+	{
+	    pj_timestamp now, next_send_ts, total_send_ts;
+
+	    total_send_ts.u64 = total_sent * stream->ts_freq.u64 * 8 /
+				stream->info.rc_cfg.bandwidth;
+	    next_send_ts = initial_time;
+	    pj_add_timestamp(&next_send_ts, &total_send_ts);
+
+	    pj_get_timestamp(&now);
+	    if (pj_cmp_timestamp(&now, &next_send_ts) < 0) {
+		unsigned ms_sleep;
+		ms_sleep = pj_elapsed_msec(&now, &next_send_ts);
+
+		if (ms_sleep > 10)
+		    ms_sleep = 10;
+
+		pj_thread_sleep(ms_sleep);
+	    }
+	}
+    }
+
+#if TRACE_RC
+    /* Trace log for rate control */
+    {
+	pj_timestamp end_time;
+	unsigned total_sleep;
+
+	pj_get_timestamp(&end_time);
+	total_sleep = pj_elapsed_msec(&initial_time, &end_time);
+	PJ_LOG(5, (stream->name.ptr, "total pkt=%d size=%d sleep=%d",
+		   pkt_cnt, total_sent, total_sleep));
+
+	if (stream->tx_start.u64 == 0)
+	    stream->tx_start = initial_time;
+	stream->tx_end = end_time;
+	stream->rc_total_pkt += pkt_cnt;
+	stream->rc_total_sleep += total_sleep;
+	stream->rc_total_img++;
+    }
+#endif
+
+    /* 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));
+    }
+
+    /* Do nothing if we have nothing to transmit */
+    if (total_sent == 0) {
+	return PJ_SUCCESS;
+    }
+
+    /* Update stat */
+    stream->rtcp.stat.rtp_tx_last_ts = pj_ntohl(stream->enc->rtp.out_hdr.ts);
+    stream->rtcp.stat.rtp_tx_last_seq = pj_ntohs(stream->enc->rtp.out_hdr.seq);
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
+    /* Update timestamp of last sending packet. */
+    stream->last_frm_ts_sent = frame->timestamp;
+#endif
+
+    return PJ_SUCCESS;
+}
+
+/* Decode one image from jitter buffer */
+static pj_status_t decode_frame(pjmedia_vid_stream *stream,
+                                pjmedia_frame *frame)
+{
+    pjmedia_vid_channel *channel = stream->dec;
+    pj_uint32_t last_ts = 0;
+    int frm_first_seq = 0, frm_last_seq = 0;
+    pj_bool_t got_frame = PJ_FALSE;
+    unsigned cnt;
+    pj_status_t status;
+
+    /* Repeat get payload from the jitter buffer until all payloads with same
+     * timestamp are collected.
+     */
+
+    /* Check if we got a decodable frame */
+    for (cnt=0; ; ++cnt) {
+	char ptype;
+	pj_uint32_t ts;
+	int seq;
+
+	/* Peek frame from jitter buffer. */
+	pjmedia_jbuf_peek_frame(stream->jb, cnt, NULL, NULL,
+				&ptype, NULL, &ts, &seq);
+	if (ptype == PJMEDIA_JB_NORMAL_FRAME) {
+	    if (last_ts == 0) {
+		last_ts = ts;
+		frm_first_seq = seq;
+	    }
+	    if (ts != last_ts) {
+		got_frame = PJ_TRUE;
+		break;
+	    }
+	    frm_last_seq = seq;
+	} else if (ptype == PJMEDIA_JB_ZERO_EMPTY_FRAME) {
+	    /* No more packet in the jitter buffer */
+	    break;
+	}
+    }
+
+    if (got_frame) {
+	unsigned i;
+
+	/* Generate frame bitstream from the payload */
+	if (cnt > stream->rx_frame_cnt) {
+	    PJ_LOG(1,(channel->port.info.name.ptr,
+		      "Discarding %u frames because array is full!",
+		      cnt - stream->rx_frame_cnt));
+	    pjmedia_jbuf_remove_frame(stream->jb, cnt - stream->rx_frame_cnt);
+	    cnt = stream->rx_frame_cnt;
+	}
+
+	for (i = 0; i < cnt; ++i) {
+	    char ptype;
+
+	    stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_VIDEO;
+	    stream->rx_frames[i].timestamp.u64 = last_ts;
+	    stream->rx_frames[i].bit_info = 0;
+
+	    /* We use jbuf_peek_frame() as it will returns the pointer of
+	     * the payload (no buffer and memcpy needed), just as we need.
+	     */
+	    pjmedia_jbuf_peek_frame(stream->jb, i,
+				    (const void**)&stream->rx_frames[i].buf,
+				    &stream->rx_frames[i].size, &ptype,
+				    NULL, NULL, NULL);
+
+	    if (ptype != PJMEDIA_JB_NORMAL_FRAME) {
+		/* Packet lost, must set payload to NULL and keep going */
+		stream->rx_frames[i].buf = NULL;
+		stream->rx_frames[i].size = 0;
+		stream->rx_frames[i].type = PJMEDIA_FRAME_TYPE_NONE;
+		continue;
+	    }
+	}
+
+	/* Decode */
+	status = pjmedia_vid_codec_decode(stream->codec, cnt,
+	                                  stream->rx_frames,
+	                                  (unsigned)frame->size, frame);
+	if (status != PJ_SUCCESS) {
+	    LOGERR_((channel->port.info.name.ptr, "codec decode() error",
+		     status));
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    frame->size = 0;
+	}
+
+	pjmedia_jbuf_remove_frame(stream->jb, cnt);
+    }
+
+    /* Learn remote frame rate after successful decoding */
+    if (frame->type == PJMEDIA_FRAME_TYPE_VIDEO && frame->size)
+    {
+	/* Only check remote frame rate when timestamp is not wrapping and
+	 * sequence is increased by 1.
+	 */
+	if (last_ts > stream->last_dec_ts &&
+	    frm_first_seq - stream->last_dec_seq == 1)
+	{
+	    pj_uint32_t ts_diff;
+	    pjmedia_video_format_detail *vfd;
+
+	    ts_diff = last_ts - stream->last_dec_ts;
+	    vfd = pjmedia_format_get_video_format_detail(
+				    &channel->port.info.fmt, PJ_TRUE);
+	    if (stream->info.codec_info.clock_rate * vfd->fps.denum !=
+		vfd->fps.num * ts_diff)
+	    {
+		/* Frame rate changed, update decoding port info */
+		if (stream->info.codec_info.clock_rate % ts_diff == 0) {
+		    vfd->fps.num = stream->info.codec_info.clock_rate/ts_diff;
+		    vfd->fps.denum = 1;
+		} else {
+		    vfd->fps.num = stream->info.codec_info.clock_rate;
+		    vfd->fps.denum = ts_diff;
+		}
+
+		/* Update stream info */
+		stream->info.codec_param->dec_fmt.det.vid.fps = vfd->fps;
+
+		/* Publish PJMEDIA_EVENT_FMT_CHANGED event if frame rate
+		 * increased and not exceeding 100fps.
+		 */
+		if (vfd->fps.num/vfd->fps.denum <= 100 &&
+		    vfd->fps.num * stream->dec_max_fps.denum >
+		    stream->dec_max_fps.num * vfd->fps.denum)
+		{
+		    pjmedia_event *event = &stream->fmt_event;
+
+		    /* Update max fps of decoding dir */
+		    stream->dec_max_fps = vfd->fps;
+
+		    /* Use the buffered format changed event:
+		     * - just update the framerate if there is pending event,
+		     * - otherwise, init the whole event.
+		     */
+		    if (stream->fmt_event.type != PJMEDIA_EVENT_NONE) {
+			event->data.fmt_changed.new_fmt.det.vid.fps = vfd->fps;
+		    } else {
+			pjmedia_event_init(event, PJMEDIA_EVENT_FMT_CHANGED,
+					   &frame->timestamp, stream);
+			event->data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
+			pj_memcpy(&event->data.fmt_changed.new_fmt,
+				  &stream->info.codec_param->dec_fmt,
+				  sizeof(pjmedia_format));
+		    }
+		}
+	    }
+	}
+
+	/* Update last frame seq and timestamp */
+	stream->last_dec_seq = frm_last_seq;
+	stream->last_dec_ts = last_ts;
+    }
+
+    return got_frame ? PJ_SUCCESS : PJ_ENOTFOUND;
+}
+
+
+static pj_status_t get_frame(pjmedia_port *port,
+                             pjmedia_frame *frame)
+{
+    pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata;
+    pjmedia_vid_channel *channel = stream->dec;
+
+    /* Return no frame is channel is paused */
+    if (channel->paused) {
+	frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	frame->size = 0;
+	return PJ_SUCCESS;
+    }
+
+    /* Report pending events. Do not publish the event while holding the
+     * jb_mutex as that would lead to deadlock. It should be safe to
+     * operate on fmt_event without the mutex because format change normally
+     * would only occur once during the start of the media.
+     */
+    if (stream->fmt_event.type != PJMEDIA_EVENT_NONE) {
+	pjmedia_event_fmt_changed_data *fmt_chg_data;
+
+	fmt_chg_data = &stream->fmt_event.data.fmt_changed;
+
+	/* Update stream info and decoding channel port info */
+	if (fmt_chg_data->dir == PJMEDIA_DIR_DECODING) {
+	    pjmedia_format_copy(&stream->info.codec_param->dec_fmt,
+				&fmt_chg_data->new_fmt);
+	    pjmedia_format_copy(&stream->dec->port.info.fmt,
+				&fmt_chg_data->new_fmt);
+
+	    /* Override the framerate to be 1.5x higher in the event
+	     * for the renderer.
+	     */
+	    fmt_chg_data->new_fmt.det.vid.fps.num *= 3;
+	    fmt_chg_data->new_fmt.det.vid.fps.num /= 2;
+	} else {
+	    pjmedia_format_copy(&stream->info.codec_param->enc_fmt,
+				&fmt_chg_data->new_fmt);
+	    pjmedia_format_copy(&stream->enc->port.info.fmt,
+				&fmt_chg_data->new_fmt);
+	}
+
+	dump_port_info(fmt_chg_data->dir==PJMEDIA_DIR_DECODING ?
+			stream->dec : stream->enc,
+		       "changed");
+
+	pjmedia_event_publish(NULL, port, &stream->fmt_event, 0);
+
+	stream->fmt_event.type = PJMEDIA_EVENT_NONE;
+    }
+
+    if (stream->miss_keyframe_event.type != PJMEDIA_EVENT_NONE) {
+	pjmedia_event_publish(NULL, port, &stream->miss_keyframe_event,
+			      PJMEDIA_EVENT_PUBLISH_POST_EVENT);
+	stream->miss_keyframe_event.type = PJMEDIA_EVENT_NONE;
+    }
+
+    pj_mutex_lock( stream->jb_mutex );
+
+    if (stream->dec_frame.size == 0) {
+	/* Don't have frame in buffer, try to decode one */
+	if (decode_frame(stream, frame) != PJ_SUCCESS) {
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    frame->size = 0;
+	}
+    } else {
+	if (frame->size < stream->dec_frame.size) {
+	    PJ_LOG(4,(stream->dec->port.info.name.ptr,
+		      "Error: not enough buffer for decoded frame "
+		      "(supplied=%d, required=%d)",
+		      (int)frame->size, (int)stream->dec_frame.size));
+	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
+	    frame->size = 0;
+	} else {
+	    frame->type = stream->dec_frame.type;
+	    frame->timestamp = stream->dec_frame.timestamp;
+	    frame->size = stream->dec_frame.size;
+	    pj_memcpy(frame->buf, stream->dec_frame.buf, frame->size);
+	}
+
+	stream->dec_frame.size = 0;
+    }
+
+    pj_mutex_unlock( stream->jb_mutex );
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Create media channel.
+ */
+static pj_status_t create_channel( pj_pool_t *pool,
+				   pjmedia_vid_stream *stream,
+				   pjmedia_dir dir,
+				   unsigned pt,
+				   const pjmedia_vid_stream_info *info,
+				   pjmedia_vid_channel **p_channel)
+{
+    enum { M = 32 };
+    pjmedia_vid_channel *channel;
+    pj_status_t status;
+    unsigned min_out_pkt_size;
+    pj_str_t name;
+    const char *type_name;
+    pjmedia_format *fmt;
+    char fourcc_name[5];
+    pjmedia_port_info *pi;
+    
+    pj_assert(info->type == PJMEDIA_TYPE_VIDEO);
+    pj_assert(dir == PJMEDIA_DIR_DECODING || dir == PJMEDIA_DIR_ENCODING);
+
+    /* Allocate memory for channel descriptor */
+    channel = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_channel);
+    PJ_ASSERT_RETURN(channel != NULL, PJ_ENOMEM);
+
+    /* Init vars */
+    if (dir==PJMEDIA_DIR_DECODING) {
+	type_name = "vstdec";
+	fmt = &info->codec_param->dec_fmt;
+    } else {
+	type_name = "vstenc";
+	fmt = &info->codec_param->enc_fmt;
+    }
+    name.ptr = (char*) pj_pool_alloc(pool, M);
+    name.slen = pj_ansi_snprintf(name.ptr, M, "%s%p", type_name, stream);
+    pi = &channel->port.info;
+
+    /* Init channel info. */
+    channel->stream = stream;
+    channel->dir = dir;
+    channel->paused = 1;
+    channel->pt = pt;
+    
+    /* Allocate buffer for outgoing packet. */
+    if (dir == PJMEDIA_DIR_ENCODING) {
+	channel->buf_size = sizeof(pjmedia_rtp_hdr) + stream->frame_size;
+
+	/* It should big enough to hold (minimally) RTCP SR with an SDES. */
+	min_out_pkt_size =  sizeof(pjmedia_rtcp_sr_pkt) +
+			    sizeof(pjmedia_rtcp_common) +
+			    (4 + (unsigned)stream->cname.slen) +
+			    32;
+
+	if (channel->buf_size < min_out_pkt_size)
+	    channel->buf_size = min_out_pkt_size;
+
+	channel->buf = pj_pool_alloc(pool, channel->buf_size);
+	PJ_ASSERT_RETURN(channel->buf != NULL, PJ_ENOMEM);
+    }
+
+    /* Create RTP and RTCP sessions: */
+    if (info->rtp_seq_ts_set == 0) {
+	status = pjmedia_rtp_session_init(&channel->rtp, pt, info->ssrc);
+    } else {
+	pjmedia_rtp_session_setting settings;
+
+	settings.flags = (pj_uint8_t)((info->rtp_seq_ts_set << 2) | 3);
+	settings.default_pt = pt;
+	settings.sender_ssrc = info->ssrc;
+	settings.seq = info->rtp_seq;
+	settings.ts = info->rtp_ts;
+	status = pjmedia_rtp_session_init2(&channel->rtp, settings);
+    }
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init port. */
+    pjmedia_port_info_init2(pi, &name, SIGNATURE, dir, fmt);
+    if (dir == PJMEDIA_DIR_DECODING) {
+	channel->port.get_frame = &get_frame;
+    } else {
+	pi->fmt.id = info->codec_param->dec_fmt.id;
+	channel->port.put_frame = &put_frame;
+    }
+
+    /* Init port. */
+    channel->port.port_data.pdata = stream;
+
+    PJ_LOG(5, (name.ptr,
+	       "%s channel created %dx%d %s%s%.*s %d/%d(~%d)fps",
+	       (dir==PJMEDIA_DIR_ENCODING?"Encoding":"Decoding"),
+	       pi->fmt.det.vid.size.w, pi->fmt.det.vid.size.h,
+	       pjmedia_fourcc_name(pi->fmt.id, fourcc_name),
+	       (dir==PJMEDIA_DIR_ENCODING?"->":"<-"),
+	       info->codec_info.encoding_name.slen,
+	       info->codec_info.encoding_name.ptr,
+	       pi->fmt.det.vid.fps.num, pi->fmt.det.vid.fps.denum,
+	       pi->fmt.det.vid.fps.num/pi->fmt.det.vid.fps.denum));
+
+    /* Done. */
+    *p_channel = channel;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Create stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_create(
+					pjmedia_endpt *endpt,
+					pj_pool_t *pool,
+					pjmedia_vid_stream_info *info,
+					pjmedia_transport *tp,
+					void *user_data,
+					pjmedia_vid_stream **p_stream)
+{
+    enum { M = 32 };
+    pj_pool_t *own_pool = NULL;
+    pjmedia_vid_stream *stream;
+    unsigned jb_init, jb_max, jb_min_pre, jb_max_pre;
+    int frm_ptime, chunks_per_frm;
+    pjmedia_video_format_detail *vfd_enc, *vfd_dec;
+    char *p;
+    pj_status_t status;
+
+    if (!pool) {
+	own_pool = pjmedia_endpt_create_pool( endpt, "vstrm%p",
+	                                      PJMEDIA_VSTREAM_SIZE,
+	                                      PJMEDIA_VSTREAM_INC);
+	PJ_ASSERT_RETURN(own_pool != NULL, PJ_ENOMEM);
+	pool = own_pool;
+    }
+
+    /* Allocate stream */
+    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_stream);
+    PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
+    stream->own_pool = own_pool;
+
+    /* Get codec manager */
+    stream->codec_mgr = pjmedia_vid_codec_mgr_instance();
+    PJ_ASSERT_RETURN(stream->codec_mgr, PJMEDIA_CODEC_EFAILED);
+
+    /* Init stream/port name */
+    stream->name.ptr = (char*) pj_pool_alloc(pool, M);
+    stream->name.slen = pj_ansi_snprintf(stream->name.ptr, M, 
+					 "vstrm%p", stream);
+
+    /* Create and initialize codec: */
+    status = pjmedia_vid_codec_mgr_alloc_codec(stream->codec_mgr, 
+					       &info->codec_info,
+					       &stream->codec);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Get codec param: */
+    if (!info->codec_param) {
+	pjmedia_vid_codec_param def_param;
+
+	status = pjmedia_vid_codec_mgr_get_default_param(stream->codec_mgr, 
+						         &info->codec_info,
+						         &def_param);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	info->codec_param = pjmedia_vid_codec_param_clone(pool, &def_param);
+	pj_assert(info->codec_param);
+    }
+
+    /* Init codec param and adjust MTU */
+    info->codec_param->dir = info->dir;
+    info->codec_param->enc_mtu -= (sizeof(pjmedia_rtp_hdr) +
+				   PJMEDIA_STREAM_RESV_PAYLOAD_LEN);
+    if (info->codec_param->enc_mtu > PJMEDIA_MAX_MTU)
+	info->codec_param->enc_mtu = PJMEDIA_MAX_MTU;
+
+    /* Packet size estimation for decoding direction */
+    vfd_enc = pjmedia_format_get_video_format_detail(
+					&info->codec_param->enc_fmt, PJ_TRUE);
+    vfd_dec = pjmedia_format_get_video_format_detail(
+					&info->codec_param->dec_fmt, PJ_TRUE);
+
+    /* Init stream: */
+    stream->endpt = endpt;
+    stream->dir = info->dir;
+    stream->user_data = user_data;
+    stream->rtcp_interval = (PJMEDIA_RTCP_INTERVAL-500 + (pj_rand()%1000)) *
+			    info->codec_info.clock_rate / 1000;
+    stream->rtcp_sdes_bye_disabled = info->rtcp_sdes_bye_disabled;
+
+    stream->jb_last_frm = PJMEDIA_JB_NORMAL_FRAME;
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
+    stream->use_ka = info->use_ka;
+#endif
+
+    /* Build random RTCP CNAME. CNAME has user@host format */
+    stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
+    pj_create_random_string(p, 5);
+    p += 5;
+    *p++ = '@'; *p++ = 'p'; *p++ = 'j';
+    pj_create_random_string(p, 6);
+    p += 6;
+    *p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
+    stream->cname.slen = p - stream->cname.ptr;
+
+
+    /* Create mutex to protect jitter buffer: */
+
+    status = pj_mutex_create_simple(pool, NULL, &stream->jb_mutex);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init and open the codec. */
+    status = pjmedia_vid_codec_init(stream->codec, pool);
+    if (status != PJ_SUCCESS)
+	return status;
+    status = pjmedia_vid_codec_open(stream->codec, info->codec_param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Subscribe to codec events */
+    pjmedia_event_subscribe(NULL, &stream_event_cb, stream,
+                            stream->codec);
+
+    /* Estimate the maximum frame size */
+    stream->frame_size = vfd_enc->size.w * vfd_enc->size.h * 4;
+
+#if 0
+    stream->frame_size = vfd_enc->max_bps/8 * vfd_enc->fps.denum /
+			 vfd_enc->fps.num;
+    
+    /* As the maximum frame_size is not represented directly by maximum bps
+     * (which includes intra and predicted frames), let's increase the
+     * frame size value for safety.
+     */
+    stream->frame_size <<= 4;
+#endif
+
+    /* Validate the frame size */
+    if (stream->frame_size == 0 || 
+	stream->frame_size > PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE)
+    {
+	stream->frame_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
+    }
+
+    /* Get frame length in timestamp unit */
+    stream->frame_ts_len = info->codec_info.clock_rate *
+                           vfd_enc->fps.denum / vfd_enc->fps.num;
+
+    /* Initialize send rate states */
+    pj_get_timestamp_freq(&stream->ts_freq);
+    if (info->rc_cfg.bandwidth == 0)
+	info->rc_cfg.bandwidth = vfd_enc->max_bps;
+
+    /* For simple blocking, need to have bandwidth large enough, otherwise
+     * we can slow down the transmission too much
+     */
+    if (info->rc_cfg.method==PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING &&
+	info->rc_cfg.bandwidth < vfd_enc->avg_bps * 3)
+    {
+	info->rc_cfg.bandwidth = vfd_enc->avg_bps * 3;
+    }
+
+    /* Override the initial framerate in the decoding direction. This initial
+     * value will be used by the renderer to configure its clock, and setting
+     * it to a bit higher value can avoid the possibility of high latency
+     * caused by clock drift (remote encoder clock runs slightly faster than
+     * local renderer clock) or video setup lag. Note that the actual framerate
+     * will be continuously calculated based on the incoming RTP timestamps.
+     */
+    vfd_dec->fps.num = vfd_dec->fps.num * 3 / 2;
+    stream->dec_max_fps = vfd_dec->fps;
+
+    /* Create decoder channel */
+    status = create_channel( pool, stream, PJMEDIA_DIR_DECODING, 
+			     info->rx_pt, info, &stream->dec);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create encoder channel */
+    status = create_channel( pool, stream, PJMEDIA_DIR_ENCODING, 
+			     info->tx_pt, info, &stream->enc);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create temporary buffer for immediate decoding */
+    stream->dec_max_size = vfd_dec->size.w * vfd_dec->size.h * 4;
+    stream->dec_frame.buf = pj_pool_alloc(pool, stream->dec_max_size);
+
+    /* Init jitter buffer parameters: */
+    frm_ptime	    = 1000 * vfd_enc->fps.denum / vfd_enc->fps.num;
+    chunks_per_frm  = stream->frame_size / PJMEDIA_MAX_MRU;
+    if (chunks_per_frm < MIN_CHUNKS_PER_FRM)
+	chunks_per_frm = MIN_CHUNKS_PER_FRM;
+
+    /* JB max count, default 500ms */
+    if (info->jb_max >= frm_ptime)
+	jb_max	    = info->jb_max * chunks_per_frm / frm_ptime;
+    else
+	jb_max	    = 500 * chunks_per_frm / frm_ptime;
+
+    /* JB min prefetch, default 1 frame */
+    if (info->jb_min_pre >= frm_ptime)
+	jb_min_pre  = info->jb_min_pre * chunks_per_frm / frm_ptime;
+    else
+	jb_min_pre  = 1;
+
+    /* JB max prefetch, default 4/5 JB max count */
+    if (info->jb_max_pre >= frm_ptime)
+	jb_max_pre  = info->jb_max_pre * chunks_per_frm / frm_ptime;
+    else
+	jb_max_pre  = jb_max * 4 / 5;
+
+    /* JB init prefetch, default 0 */
+    if (info->jb_init >= frm_ptime)
+	jb_init  = info->jb_init * chunks_per_frm / frm_ptime;
+    else
+	jb_init  = 0;
+
+    /* Allocate array for temporary storage for assembly of incoming
+     * frames. Add more just in case.
+     */
+    stream->rx_frame_cnt = chunks_per_frm * 2;
+    stream->rx_frames = pj_pool_calloc(pool, stream->rx_frame_cnt,
+                                       sizeof(stream->rx_frames[0]));
+
+    /* Create jitter buffer */
+    status = pjmedia_jbuf_create(pool, &stream->dec->port.info.name,
+                                 PJMEDIA_MAX_MRU,
+				 1000 * vfd_enc->fps.denum / vfd_enc->fps.num,
+				 jb_max, &stream->jb);
+    if (status != PJ_SUCCESS)
+	return status;
+
+
+    /* Set up jitter buffer */
+    pjmedia_jbuf_set_adaptive(stream->jb, jb_init, jb_min_pre, jb_max_pre);
+    pjmedia_jbuf_set_discard(stream->jb, PJMEDIA_JB_DISCARD_NONE);
+
+    /* Init RTCP session: */
+    {
+	pjmedia_rtcp_session_setting rtcp_setting;
+
+	pjmedia_rtcp_session_setting_default(&rtcp_setting);
+	rtcp_setting.name = stream->name.ptr;
+	rtcp_setting.ssrc = info->ssrc;
+	rtcp_setting.rtp_ts_base = pj_ntohl(stream->enc->rtp.out_hdr.ts);
+	rtcp_setting.clock_rate = info->codec_info.clock_rate;
+	rtcp_setting.samples_per_frame = 1;
+
+	pjmedia_rtcp_init2(&stream->rtcp, &rtcp_setting);
+    }
+
+    /* Allocate outgoing RTCP buffer, should be enough to hold SR/RR, SDES,
+     * BYE, and XR.
+     */
+    stream->out_rtcp_pkt_size =  sizeof(pjmedia_rtcp_sr_pkt) +
+				 sizeof(pjmedia_rtcp_common) +
+				 (4 + (unsigned)stream->cname.slen) +
+				 32;
+    if (stream->out_rtcp_pkt_size > PJMEDIA_MAX_MTU)
+	stream->out_rtcp_pkt_size = PJMEDIA_MAX_MTU;
+
+    stream->out_rtcp_pkt = pj_pool_alloc(pool, stream->out_rtcp_pkt_size);
+
+    /* Only attach transport when stream is ready. */
+    status = pjmedia_transport_attach(tp, stream, &info->rem_addr, 
+				      &info->rem_rtcp, 
+				      pj_sockaddr_get_len(&info->rem_addr), 
+                                      &on_rx_rtp, &on_rx_rtcp);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    stream->transport = tp;
+
+    /* Send RTCP SDES */
+    if (!stream->rtcp_sdes_bye_disabled) {
+        pjmedia_vid_stream_send_rtcp_sdes(stream);
+    }
+
+#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
+    /* NAT hole punching by sending KA packet via RTP transport. */
+    if (stream->use_ka)
+	send_keep_alive_packet(stream);
+#endif
+
+#if TRACE_JB
+    {
+	char trace_name[PJ_MAXPATH];
+	pj_ssize_t len;
+
+	pj_ansi_snprintf(trace_name, sizeof(trace_name), 
+			 TRACE_JB_PATH_PREFIX "%s.csv",
+			 channel->port.info.name.ptr);
+	status = pj_file_open(pool, trace_name, PJ_O_RDWR,
+			      &stream->trace_jb_fd);
+	if (status != PJ_SUCCESS) {
+	    stream->trace_jb_fd = TRACE_JB_INVALID_FD;
+	    PJ_LOG(3,(THIS_FILE, "Failed creating RTP trace file '%s'", 
+		      trace_name));
+	} else {
+	    stream->trace_jb_buf = (char*)pj_pool_alloc(pool, PJ_LOG_MAX_SIZE);
+
+	    /* Print column header */
+	    len = pj_ansi_snprintf(stream->trace_jb_buf, PJ_LOG_MAX_SIZE,
+				   "Time, Operation, Size, Frame Count, "
+				   "Frame type, RTP Seq, RTP TS, RTP M, "
+				   "JB size, JB burst level, JB prefetch\n");
+	    if (len < 1 || len >= PJ_LOG_MAX_SIZE)
+		len = PJ_LOG_MAX_SIZE - 1;
+	    pj_file_write(stream->trace_jb_fd, stream->trace_jb_buf, &len);
+	    pj_file_flush(stream->trace_jb_fd);
+	}
+    }
+#endif
+
+    /* Save the stream info */
+    pj_memcpy(&stream->info, info, sizeof(*info));
+    stream->info.codec_param = pjmedia_vid_codec_param_clone(
+						pool, info->codec_param);
+
+    /* Success! */
+    *p_stream = stream;
+
+    PJ_LOG(5,(THIS_FILE, "Video stream %s created", stream->name.ptr));
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Destroy stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_destroy( pjmedia_vid_stream *stream )
+{
+    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+#if TRACE_RC
+    {
+	unsigned total_time;
+
+	total_time = pj_elapsed_msec(&stream->tx_start, &stream->tx_end);
+	PJ_LOG(5, (stream->name.ptr, 
+		   "RC stat: pkt_cnt=%.2f/image, sleep=%.2fms/s, fps=%.2f",
+		   stream->rc_total_pkt*1.0/stream->rc_total_img,
+		   stream->rc_total_sleep*1000.0/total_time,
+		   stream->rc_total_img*1000.0/total_time));
+    }
+#endif
+
+    /* Send RTCP BYE (also SDES) */
+    if (!stream->rtcp_sdes_bye_disabled) {
+	send_rtcp(stream, PJ_TRUE, PJ_TRUE);
+    }
+
+    /* Detach from transport 
+     * MUST NOT hold stream mutex while detaching from transport, as
+     * it may cause deadlock. See ticket #460 for the details.
+     */
+    if (stream->transport) {
+	pjmedia_transport_detach(stream->transport, stream);
+	stream->transport = NULL;
+    }
+
+    /* This function may be called when stream is partly initialized. */
+    if (stream->jb_mutex)
+	pj_mutex_lock(stream->jb_mutex);
+
+
+    /* Free codec. */
+    if (stream->codec) {
+        pjmedia_event_unsubscribe(NULL, &stream_event_cb, stream,
+                                  stream->codec);
+	pjmedia_vid_codec_close(stream->codec);
+	pjmedia_vid_codec_mgr_dealloc_codec(stream->codec_mgr, stream->codec);
+	stream->codec = NULL;
+    }
+
+    /* Free mutex */
+    
+    if (stream->jb_mutex) {
+	pj_mutex_destroy(stream->jb_mutex);
+	stream->jb_mutex = NULL;
+    }
+
+    /* Destroy jitter buffer */
+    if (stream->jb) {
+	pjmedia_jbuf_destroy(stream->jb);
+	stream->jb = NULL;
+    }
+
+#if TRACE_JB
+    if (TRACE_JB_OPENED(stream)) {
+	pj_file_close(stream->trace_jb_fd);
+	stream->trace_jb_fd = TRACE_JB_INVALID_FD;
+    }
+#endif
+
+    if (stream->own_pool) {
+	pj_pool_t *pool = stream->own_pool;
+	stream->own_pool = NULL;
+	pj_pool_release(pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the port interface.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_get_port(pjmedia_vid_stream *stream,
+						pjmedia_dir dir,
+						pjmedia_port **p_port )
+{
+    PJ_ASSERT_RETURN(dir==PJMEDIA_DIR_ENCODING || dir==PJMEDIA_DIR_DECODING,
+		     PJ_EINVAL);
+
+    if (dir == PJMEDIA_DIR_ENCODING)
+	*p_port = &stream->enc->port;
+    else
+	*p_port = &stream->dec->port;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the transport object
+ */
+PJ_DEF(pjmedia_transport*) pjmedia_vid_stream_get_transport(
+						    pjmedia_vid_stream *st)
+{
+    return st->transport;
+}
+
+
+/*
+ * Get stream statistics.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_get_stat(
+					    const pjmedia_vid_stream *stream,
+					    pjmedia_rtcp_stat *stat)
+{
+    PJ_ASSERT_RETURN(stream && stat, PJ_EINVAL);
+
+    pj_memcpy(stat, &stream->rtcp.stat, sizeof(pjmedia_rtcp_stat));
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Reset the stream statistics in the middle of a stream session.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_reset_stat(pjmedia_vid_stream *stream)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    pjmedia_rtcp_init_stat(&stream->rtcp.stat);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get jitter buffer state.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_get_stat_jbuf(
+					    const pjmedia_vid_stream *stream,
+					    pjmedia_jb_state *state)
+{
+    PJ_ASSERT_RETURN(stream && state, PJ_EINVAL);
+    return pjmedia_jbuf_get_state(stream->jb, state);
+}
+
+
+/*
+ * Get the stream info.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_get_info(
+					    const pjmedia_vid_stream *stream,
+					    pjmedia_vid_stream_info *info)
+{
+    PJ_ASSERT_RETURN(stream && info, PJ_EINVAL);
+    pj_memcpy(info, &stream->info, sizeof(*info));
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Start stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_start(pjmedia_vid_stream *stream)
+{
+
+    PJ_ASSERT_RETURN(stream && stream->enc && stream->dec, PJ_EINVALIDOP);
+
+    if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) {
+	stream->enc->paused = 0;
+	//pjmedia_snd_stream_start(stream->enc->snd_stream);
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream started"));
+    } else {
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
+    }
+
+    if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) {
+	stream->dec->paused = 0;
+	//pjmedia_snd_stream_start(stream->dec->snd_stream);
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream started"));
+    } else {
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Check status.
+ */
+PJ_DEF(pj_bool_t) pjmedia_vid_stream_is_running(pjmedia_vid_stream *stream,
+                                                pjmedia_dir dir)
+{
+    pj_bool_t is_running = PJ_TRUE;
+
+    PJ_ASSERT_RETURN(stream, PJ_FALSE);
+
+    if (dir & PJMEDIA_DIR_ENCODING) {
+	is_running &= (stream->enc && !stream->enc->paused);
+    }
+
+    if (dir & PJMEDIA_DIR_DECODING) {
+	is_running &= (stream->dec && !stream->dec->paused);
+    }
+
+    return is_running;
+}
+
+/*
+ * Pause stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_pause(pjmedia_vid_stream *stream,
+					     pjmedia_dir dir)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
+	stream->enc->paused = 1;
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream paused"));
+    }
+
+    if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
+	stream->dec->paused = 1;
+
+	/* Also reset jitter buffer */
+	pj_mutex_lock( stream->jb_mutex );
+	pjmedia_jbuf_reset(stream->jb);
+	pj_mutex_unlock( stream->jb_mutex );
+
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream paused"));
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Resume stream
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_resume(pjmedia_vid_stream *stream,
+					      pjmedia_dir dir)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) {
+	stream->enc->paused = 0;
+	PJ_LOG(4,(stream->enc->port.info.name.ptr, "Encoder stream resumed"));
+    }
+
+    if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) {
+	stream->dec->paused = 0;
+	PJ_LOG(4,(stream->dec->port.info.name.ptr, "Decoder stream resumed"));
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Force stream to send video keyframe.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_send_keyframe(
+						pjmedia_vid_stream *stream)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if (!pjmedia_vid_stream_is_running(stream, PJMEDIA_DIR_ENCODING))
+	return PJ_EINVALIDOP;
+
+    stream->force_keyframe = PJ_TRUE;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Send RTCP SDES.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_sdes(
+						pjmedia_vid_stream *stream)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    return send_rtcp(stream, PJ_TRUE, PJ_FALSE);
+}
+
+
+/*
+ * Send RTCP BYE.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_bye(
+						pjmedia_vid_stream *stream)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if (stream->enc && stream->transport) {
+	return send_rtcp(stream, PJ_TRUE, PJ_TRUE);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize the video stream rate control with default settings.
+ */
+PJ_DEF(void)
+pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config *cfg)
+{
+    pj_bzero(cfg, sizeof(*cfg));
+    cfg->method = PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING;
+}
+
+
+#endif /* PJMEDIA_HAS_VIDEO */
diff --git a/jni/pjproject-android/.svn/pristine/c9/c960951313aaa0f9fdfaff89b1da28b8a9a19435.svn-base b/jni/pjproject-android/.svn/pristine/c9/c960951313aaa0f9fdfaff89b1da28b8a9a19435.svn-base
new file mode 100644
index 0000000..a3b3021
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c960951313aaa0f9fdfaff89b1da28b8a9a19435.svn-base
@@ -0,0 +1,28 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = ["m=audio \d+ RTP/SAVP", "a=crypto"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP optional receive RTP/SAVP, should answer RTP/SAVP too", 
+			    pjsua_args=args, sdp=sdp, resp_code=200, 
+			    resp_inc=include, resp_exc=exclude)
+
diff --git a/jni/pjproject-android/.svn/pristine/c9/c9647178a81b7959d177b39f30f5a3f76cc8dcf6.svn-base b/jni/pjproject-android/.svn/pristine/c9/c9647178a81b7959d177b39f30f5a3f76cc8dcf6.svn-base
new file mode 100644
index 0000000..0f04c8f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c9647178a81b7959d177b39f30f5a3f76cc8dcf6.svn-base
@@ -0,0 +1,138 @@
+

+!IF "$(OS)" == "Windows_NT"

+NULL=

+!ELSE 

+NULL=nul

+!ENDIF 

+

+CPP=cl.exe

+RSC=rc.exe

+F90=df.exe

+BSC32=bscmake.exe

+BSC32_SBRS= \

+	

+LIB32=link.exe -lib

+

+OUTDIR_REL=.\output\libsamplerate-i386-win32-vc-release

+INTDIR_REL=.\output\libsamplerate-i386-win32-vc-release

+OUTDIR_DEB=.\output\libsamplerate-i386-win32-vc-debug

+INTDIR_DEB=.\output\libsamplerate-i386-win32-vc-debug

+

+LIB_REL=..\..\lib\libsamplerate-i386-win32-vc-release.lib

+LIB_DEB=..\..\lib\libsamplerate-i386-win32-vc-debug.lib

+

+ALL : $(LIB_REL) $(LIB_DEB)

+

+CLEAN :

+	-@erase "$(INTDIR_REL)\*.obj"

+	-@erase "$(INTDIR_REL)\*.pch"

+	-@erase "$(INTDIR_REL)\*.pdb"

+	-@erase "$(INTDIR_REL)\*.idb"

+	@rmdir $(INTDIR_REL)

+	-@erase "$(INTDIR_DEB)\*.obj"

+	-@erase "$(INTDIR_DEB)\*.pch"

+	-@erase "$(INTDIR_DEB)\*.pdb"

+	-@erase "$(INTDIR_DEB)\*.idb"

+	@rmdir $(INTDIR_DEB)

+	-@erase $(LIB_REL)

+	-@erase $(LIB_DEB)

+

+"$(OUTDIR_REL)" :

+    if not exist "$(OUTDIR_REL)/$(NULL)" mkdir "$(OUTDIR_REL)"

+

+CPP_PROJ_REL=/nologo /MD /W3 /GX /O2 /I "../win32" /I "../../libsamplerate/src" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /Fp"$(INTDIR_REL)\libsamplerate_static.pch" /YX /Fo"$(INTDIR_REL)\\" /Fd"$(INTDIR_REL)\\" /FD /c 

+	

+LIB32_FLAGS_REL=/nologo /out:$(LIB_REL)

+LIB32_OBJS_REL= \

+	"$(INTDIR_REL)\samplerate.obj" \

+	"$(INTDIR_REL)\src_linear.obj" \

+	"$(INTDIR_REL)\src_sinc.obj" \

+	"$(INTDIR_REL)\src_zoh.obj"

+

+$(LIB_REL) : "$(OUTDIR_REL)" $(DEF_FILE) $(LIB32_OBJS_REL)

+    $(LIB32) @<<

+  $(LIB32_FLAGS_REL) $(DEF_FLAGS) $(LIB32_OBJS_REL)

+<<

+

+"$(OUTDIR_DEB)" :

+    if not exist "$(OUTDIR_DEB)/$(NULL)" mkdir "$(OUTDIR_DEB)"

+

+CPP_PROJ_DEB=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "../win32" /I "../../libsamplerate/src" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /Fp"$(INTDIR_DEB)\libsamplerate_static.pch" /YX /Fo"$(INTDIR_DEB)\\" /Fd"$(INTDIR_DEB)\\" /FD /GZ /c 

+LIB32_FLAGS_DEB=/nologo /out:$(LIB_DEB)

+LIB32_OBJS_DEB= \

+	"$(INTDIR_DEB)\samplerate.obj" \

+	"$(INTDIR_DEB)\src_linear.obj" \

+	"$(INTDIR_DEB)\src_sinc.obj" \

+	"$(INTDIR_DEB)\src_zoh.obj"

+

+$(LIB_DEB) : "$(OUTDIR_DEB)" $(DEF_FILE) $(LIB32_OBJS_DEB)

+    $(LIB32) @<<

+  $(LIB32_FLAGS_DEB) $(DEF_FLAGS) $(LIB32_OBJS_DEB)

+<<

+

+

+..\..\libsamplerate\src\samplerate.c : \

+	"..\..\libsamplerate\src\common.h"\

+	"..\..\libsamplerate\src\config.h"\

+	"..\..\libsamplerate\src\float_cast.h"\

+	"..\..\libsamplerate\src\samplerate.h"\

+	

+

+..\..\libsamplerate\src\src_linear.c : \

+	"..\..\libsamplerate\src\common.h"\

+	"..\..\libsamplerate\src\config.h"\

+	"..\..\libsamplerate\src\float_cast.h"\

+	"..\..\libsamplerate\src\samplerate.h"\

+	

+

+..\..\libsamplerate\src\src_sinc.c : \

+	"..\..\libsamplerate\src\common.h"\

+	"..\..\libsamplerate\src\config.h"\

+	"..\..\libsamplerate\src\fastest_coeffs.h"\

+	"..\..\libsamplerate\src\float_cast.h"\

+	"..\..\libsamplerate\src\high_qual_coeffs.h"\

+	"..\..\libsamplerate\src\mid_qual_coeffs.h"\

+	"..\..\libsamplerate\src\samplerate.h"\

+	

+

+..\..\libsamplerate\src\src_zoh.c : \

+	"..\..\libsamplerate\src\common.h"\

+	"..\..\libsamplerate\src\config.h"\

+	"..\..\libsamplerate\src\float_cast.h"\

+	"..\..\libsamplerate\src\samplerate.h"\

+	

+

+

+SOURCE=..\..\libsamplerate\src\samplerate.c

+

+"$(INTDIR_DEB)\samplerate.obj" : $(SOURCE) "$(INTDIR_DEB)"

+	$(CPP) $(CPP_PROJ_DEB) $(SOURCE)

+"$(INTDIR_REL)\samplerate.obj" : $(SOURCE) "$(INTDIR_REL)"

+	$(CPP) $(CPP_PROJ_REL) $(SOURCE)

+

+

+SOURCE=..\..\libsamplerate\src\src_linear.c

+

+"$(INTDIR_DEB)\src_linear.obj" : $(SOURCE) "$(INTDIR_DEB)"

+	$(CPP) $(CPP_PROJ_DEB) $(SOURCE)

+"$(INTDIR_REL)\src_linear.obj" : $(SOURCE) "$(INTDIR_REL)"

+	$(CPP) $(CPP_PROJ_REL) $(SOURCE)

+

+

+SOURCE=..\..\libsamplerate\src\src_sinc.c

+

+"$(INTDIR_DEB)\src_sinc.obj" : $(SOURCE) "$(INTDIR_DEB)"

+	$(CPP) $(CPP_PROJ_DEB) $(SOURCE)

+"$(INTDIR_REL)\src_sinc.obj" : $(SOURCE) "$(INTDIR_REL)"

+	$(CPP) $(CPP_PROJ_REL) $(SOURCE)

+

+

+SOURCE=..\..\libsamplerate\src\src_zoh.c

+

+"$(INTDIR_DEB)\src_zoh.obj" : $(SOURCE) "$(INTDIR_DEB)"

+	$(CPP) $(CPP_PROJ_DEB) $(SOURCE)

+"$(INTDIR_REL)\src_zoh.obj" : $(SOURCE) "$(INTDIR_REL)"

+	$(CPP) $(CPP_PROJ_REL) $(SOURCE)

+

+

+

diff --git a/jni/pjproject-android/.svn/pristine/c9/c97543a2975cbd4ef88efa208afc0aabab86f588.svn-base b/jni/pjproject-android/.svn/pristine/c9/c97543a2975cbd4ef88efa208afc0aabab86f588.svn-base
new file mode 100644
index 0000000..3811acf
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c97543a2975cbd4ef88efa208afc0aabab86f588.svn-base
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.teluu.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UIBackgroundModes</key>
+	<array>
+		<string>audio</string>
+		<string>voip</string>
+	</array>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+	</array>
+</dict>
+</plist>
diff --git a/jni/pjproject-android/.svn/pristine/c9/c9af3e6a9176c2a9d12a1ce07ce969d4be1d6c52.svn-base b/jni/pjproject-android/.svn/pristine/c9/c9af3e6a9176c2a9d12a1ce07ce969d4be1d6c52.svn-base
new file mode 100644
index 0000000..0ecb826
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/c9/c9af3e6a9176c2a9d12a1ce07ce969d4be1d6c52.svn-base
@@ -0,0 +1,44 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/unicode.h>
+
+#include "os_symbian.h"
+#include <e32cons.h>
+
+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
+{
+#if 0
+    wchar_t wbuffer[PJ_LOG_MAX_SIZE];
+    CConsoleBase *cons = PjSymbianOS::Instance->Console();
+
+    pj_ansi_to_unicode(buffer, len, wbuffer, PJ_ARRAY_SIZE(wbuffer));
+
+    
+    TPtrC16 aPtr((TUint16*)wbuffer, len);
+    console->Write(aPtr);
+#else
+    PJ_UNUSED_ARG(level);
+    PJ_UNUSED_ARG(buffer);
+    PJ_UNUSED_ARG(len);
+#endif
+}
+