* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef02aa403c02083b4d783c589a38d537a7f6c885.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef02aa403c02083b4d783c589a38d537a7f6c885.svn-base
new file mode 100644
index 0000000..0804d7a
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef02aa403c02083b4d783c589a38d537a7f6c885.svn-base
@@ -0,0 +1,1453 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-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-videodev/videodev_imp.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/os.h>
+
+#if defined(PJMEDIA_VIDEO_DEV_HAS_SDL) && PJMEDIA_VIDEO_DEV_HAS_SDL != 0
+#include <SDL.h>
+#include <SDL_syswm.h>
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+#   include "SDL_opengl.h"
+#   define OPENGL_DEV_IDX 1
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+#if !(SDL_VERSION_ATLEAST(1,3,0))
+#   error "SDL 1.3 or later is required"
+#endif
+
+#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
+#   include "TargetConditionals.h"
+#   include <Foundation/Foundation.h>
+#endif
+
+#define THIS_FILE		"sdl_dev.c"
+#define DEFAULT_CLOCK_RATE	90000
+#define DEFAULT_WIDTH		640
+#define DEFAULT_HEIGHT		480
+#define DEFAULT_FPS		25
+
+typedef struct sdl_fmt_info
+{
+    pjmedia_format_id   fmt_id;
+    Uint32              sdl_format;
+    Uint32              Rmask;
+    Uint32              Gmask;
+    Uint32              Bmask;
+    Uint32              Amask;
+} sdl_fmt_info;
+
+static sdl_fmt_info sdl_fmts[] =
+{
+#if PJ_IS_BIG_ENDIAN
+    {PJMEDIA_FORMAT_RGBA,  (Uint32)SDL_PIXELFORMAT_RGBA8888,
+     0xFF000000, 0xFF0000, 0xFF00, 0xFF} ,
+    {PJMEDIA_FORMAT_RGB24, (Uint32)SDL_PIXELFORMAT_RGB24,
+     0xFF0000, 0xFF00, 0xFF, 0} ,
+    {PJMEDIA_FORMAT_BGRA,  (Uint32)SDL_PIXELFORMAT_BGRA8888,
+     0xFF00, 0xFF0000, 0xFF000000, 0xFF} ,
+#else /* PJ_IS_BIG_ENDIAN */
+    {PJMEDIA_FORMAT_RGBA,  (Uint32)SDL_PIXELFORMAT_ABGR8888,
+     0xFF, 0xFF00, 0xFF0000, 0xFF000000} ,
+    {PJMEDIA_FORMAT_RGB24, (Uint32)SDL_PIXELFORMAT_BGR24,
+     0xFF, 0xFF00, 0xFF0000, 0} ,
+    {PJMEDIA_FORMAT_BGRA,  (Uint32)SDL_PIXELFORMAT_ARGB8888,
+     0xFF0000, 0xFF00, 0xFF, 0xFF000000} ,
+#endif /* PJ_IS_BIG_ENDIAN */
+
+    {PJMEDIA_FORMAT_DIB , (Uint32)SDL_PIXELFORMAT_RGB24,
+     0xFF0000, 0xFF00, 0xFF, 0} ,
+
+    {PJMEDIA_FORMAT_YUY2, SDL_PIXELFORMAT_YUY2, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_UYVY, SDL_PIXELFORMAT_UYVY, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_YVYU, SDL_PIXELFORMAT_YVYU, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_I420, SDL_PIXELFORMAT_IYUV, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_YV12, SDL_PIXELFORMAT_YV12, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_I420JPEG, SDL_PIXELFORMAT_IYUV, 0, 0, 0, 0} ,
+    {PJMEDIA_FORMAT_I422JPEG, SDL_PIXELFORMAT_YV12, 0, 0, 0, 0}
+};
+
+/* sdl_ device info */
+struct sdl_dev_info
+{
+    pjmedia_vid_dev_info	 info;
+};
+
+/* Linked list of streams */
+struct stream_list
+{
+    PJ_DECL_LIST_MEMBER(struct stream_list);
+    struct sdl_stream	*stream;
+};
+
+#define INITIAL_MAX_JOBS 64
+#define JOB_QUEUE_INC_FACTOR 2
+
+typedef pj_status_t (*job_func_ptr)(void *data);
+
+typedef struct job {
+    job_func_ptr    func;
+    void           *data;
+    unsigned        flags;
+    pj_status_t     retval;
+} job;
+
+#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
+@interface JQDelegate: NSObject
+{
+    @public
+    job *pjob;
+}
+
+- (void)run_job;
+@end
+
+@implementation JQDelegate
+- (void)run_job
+{
+    pjob->retval = (*pjob->func)(pjob->data);
+}
+@end
+#endif /* PJ_DARWINOS */
+
+typedef struct job_queue {
+    pj_pool_t      *pool;
+    job           **jobs;
+    pj_sem_t      **job_sem;
+    pj_sem_t      **old_sem;
+    pj_mutex_t     *mutex;
+    pj_thread_t    *thread;
+    pj_sem_t       *sem;
+
+    unsigned        size;
+    unsigned        head, tail;
+    pj_bool_t	    is_full;
+    pj_bool_t       is_quitting;
+} job_queue;
+
+/* sdl_ factory */
+struct sdl_factory
+{
+    pjmedia_vid_dev_factory	 base;
+    pj_pool_t			*pool;
+    pj_pool_factory		*pf;
+
+    unsigned			 dev_count;
+    struct sdl_dev_info	        *dev_info;
+    job_queue                   *jq;
+
+    pj_thread_t			*sdl_thread;        /**< SDL thread.        */
+    pj_sem_t                    *sem;
+    pj_mutex_t			*mutex;
+    struct stream_list		 streams;
+    pj_bool_t                    is_quitting;
+    pj_thread_desc 		 thread_desc;
+    pj_thread_t 		*ev_thread;
+};
+
+/* Video stream. */
+struct sdl_stream
+{
+    pjmedia_vid_dev_stream	 base;		    /**< Base stream	    */
+    pjmedia_vid_dev_param	 param;		    /**< Settings	    */
+    pj_pool_t			*pool;              /**< Memory pool.       */
+
+    pjmedia_vid_dev_cb		 vid_cb;            /**< Stream callback.   */
+    void			*user_data;         /**< Application data.  */
+
+    struct sdl_factory          *sf;
+    const pjmedia_frame         *frame;
+    pj_bool_t			 is_running;
+    pj_timestamp		 last_ts;
+    struct stream_list		 list_entry;
+
+    SDL_Window                  *window;            /**< Display window.    */
+    SDL_Renderer                *renderer;          /**< Display renderer.  */
+    SDL_Texture                 *scr_tex;           /**< Screen texture.    */
+    int                          pitch;             /**< Pitch value.       */
+    SDL_Rect			 rect;              /**< Frame rectangle.   */
+    SDL_Rect			 dstrect;           /**< Display rectangle. */
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    SDL_GLContext               *gl_context;
+    GLuint			 texture;
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+    pjmedia_video_apply_fmt_param vafp;
+};
+
+/* Prototypes */
+static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f);
+static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f);
+static pj_status_t sdl_factory_refresh(pjmedia_vid_dev_factory *f);
+static unsigned    sdl_factory_get_dev_count(pjmedia_vid_dev_factory *f);
+static pj_status_t sdl_factory_get_dev_info(pjmedia_vid_dev_factory *f,
+					    unsigned index,
+					    pjmedia_vid_dev_info *info);
+static pj_status_t sdl_factory_default_param(pj_pool_t *pool,
+                                             pjmedia_vid_dev_factory *f,
+					     unsigned index,
+					     pjmedia_vid_dev_param *param);
+static pj_status_t sdl_factory_create_stream(
+					pjmedia_vid_dev_factory *f,
+					pjmedia_vid_dev_param *param,
+					const pjmedia_vid_dev_cb *cb,
+					void *user_data,
+					pjmedia_vid_dev_stream **p_vid_strm);
+
+static pj_status_t sdl_stream_get_param(pjmedia_vid_dev_stream *strm,
+					pjmedia_vid_dev_param *param);
+static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *strm,
+				      pjmedia_vid_dev_cap cap,
+				      void *value);
+static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *strm,
+				      pjmedia_vid_dev_cap cap,
+				      const void *value);
+static pj_status_t sdl_stream_put_frame(pjmedia_vid_dev_stream *strm,
+                                        const pjmedia_frame *frame);
+static pj_status_t sdl_stream_start(pjmedia_vid_dev_stream *strm);
+static pj_status_t sdl_stream_stop(pjmedia_vid_dev_stream *strm);
+static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm);
+
+static pj_status_t resize_disp(struct sdl_stream *strm,
+                               pjmedia_rect_size *new_disp_size);
+static pj_status_t sdl_destroy_all(void *data);
+
+/* Job queue prototypes */
+static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq);
+static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func,
+				      void *data, unsigned flags,
+				      pj_status_t *retval);
+static pj_status_t job_queue_destroy(job_queue *jq);
+
+/* Operations */
+static pjmedia_vid_dev_factory_op factory_op =
+{
+    &sdl_factory_init,
+    &sdl_factory_destroy,
+    &sdl_factory_get_dev_count,
+    &sdl_factory_get_dev_info,
+    &sdl_factory_default_param,
+    &sdl_factory_create_stream,
+    &sdl_factory_refresh
+};
+
+static pjmedia_vid_dev_stream_op stream_op =
+{
+    &sdl_stream_get_param,
+    &sdl_stream_get_cap,
+    &sdl_stream_set_cap,
+    &sdl_stream_start,
+    NULL,
+    &sdl_stream_put_frame,
+    &sdl_stream_stop,
+    &sdl_stream_destroy
+};
+
+/*
+ * Util
+ */
+static void sdl_log_err(const char *op)
+{
+    PJ_LOG(1,(THIS_FILE, "%s error: %s", op, SDL_GetError()));
+}
+
+/****************************************************************************
+ * Factory operations
+ */
+/*
+ * Init sdl_ video driver.
+ */
+pjmedia_vid_dev_factory* pjmedia_sdl_factory(pj_pool_factory *pf)
+{
+    struct sdl_factory *f;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "sdl video", 1000, 1000, NULL);
+    f = PJ_POOL_ZALLOC_T(pool, struct sdl_factory);
+    f->pf = pf;
+    f->pool = pool;
+    f->base.op = &factory_op;
+
+    return &f->base;
+}
+
+static pj_status_t sdl_init(void * data)
+{
+    PJ_UNUSED_ARG(data);
+
+    if (SDL_Init(SDL_INIT_VIDEO)) {
+        sdl_log_err("SDL_Init()");
+        return PJMEDIA_EVID_INIT;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static struct sdl_stream* find_stream(struct sdl_factory *sf,
+                                      Uint32 windowID,
+                                      pjmedia_event *pevent)
+{
+    struct stream_list *it, *itBegin;
+    struct sdl_stream *strm = NULL;
+
+    itBegin = &sf->streams;
+    for (it = itBegin->next; it != itBegin; it = it->next) {
+        if (SDL_GetWindowID(it->stream->window) == windowID)
+        {
+            strm = it->stream;
+            break;
+        }
+    }
+ 
+    if (strm)
+        pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts,
+		           strm);
+
+    return strm;
+}
+
+static pj_status_t handle_event(void *data)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)data;
+    SDL_Event sevent;
+
+    if (!pj_thread_is_registered())
+	pj_thread_register("sdl_ev", sf->thread_desc, &sf->ev_thread);
+
+    while (SDL_PollEvent(&sevent)) {
+        struct sdl_stream *strm = NULL;
+        pjmedia_event pevent;
+
+        pj_mutex_lock(sf->mutex);
+        pevent.type = PJMEDIA_EVENT_NONE;
+	switch(sevent.type) {
+        case SDL_MOUSEBUTTONDOWN:
+            strm = find_stream(sf, sevent.button.windowID, &pevent);
+            pevent.type = PJMEDIA_EVENT_MOUSE_BTN_DOWN;
+            break;
+        case SDL_WINDOWEVENT:
+            strm = find_stream(sf, sevent.window.windowID, &pevent);
+            switch (sevent.window.event) {
+            case SDL_WINDOWEVENT_RESIZED:
+                pevent.type = PJMEDIA_EVENT_WND_RESIZED;
+                pevent.data.wnd_resized.new_size.w =
+                    sevent.window.data1;
+                pevent.data.wnd_resized.new_size.h =
+                    sevent.window.data2;
+                break;
+            case SDL_WINDOWEVENT_CLOSE:
+                pevent.type = PJMEDIA_EVENT_WND_CLOSING;
+                break;
+            }
+            break;
+        default:
+            break;
+	}
+
+        if (strm && pevent.type != PJMEDIA_EVENT_NONE) {
+            pj_status_t status;
+
+	    pjmedia_event_publish(NULL, strm, &pevent, 0);
+
+	    switch (pevent.type) {
+	    case PJMEDIA_EVENT_WND_RESIZED:
+                status = resize_disp(strm, &pevent.data.wnd_resized.new_size);
+                if (status != PJ_SUCCESS)
+                    PJ_LOG(3, (THIS_FILE, "Failed resizing the display."));
+		break;
+	    case PJMEDIA_EVENT_WND_CLOSING:
+		if (pevent.data.wnd_closing.cancel) {
+		    /* Cancel the closing operation */
+		    break;
+		}
+
+		/* Proceed to cleanup SDL. App must still call
+		 * pjmedia_dev_stream_destroy() when getting WND_CLOSED
+		 * event
+		 */
+		sdl_stream_stop(&strm->base);
+                sdl_destroy_all(strm);
+                pjmedia_event_init(&pevent, PJMEDIA_EVENT_WND_CLOSED,
+                                   &strm->last_ts, strm);
+                pjmedia_event_publish(NULL, strm, &pevent, 0);
+
+                /*
+                 * Note: don't access the stream after this point, it
+                 * might have been destroyed
+                 */
+                break;
+	    default:
+		/* Just to prevent gcc warning about unused enums */
+		break;
+	    }
+        }
+
+        pj_mutex_unlock(sf->mutex);
+    }
+
+    return PJ_SUCCESS;
+}
+
+static int sdl_ev_thread(void *data)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)data;
+
+    while(1) {
+        pj_status_t status;
+
+        pj_mutex_lock(sf->mutex);
+        if (pj_list_empty(&sf->streams)) {
+            pj_mutex_unlock(sf->mutex);
+            /* Wait until there is any stream. */
+            pj_sem_wait(sf->sem);
+        } else
+            pj_mutex_unlock(sf->mutex);
+
+        if (sf->is_quitting)
+            break;
+
+        job_queue_post_job(sf->jq, handle_event, sf, 0, &status);
+
+        pj_thread_sleep(50);
+    }
+
+    return 0;
+}
+
+static pj_status_t sdl_quit(void *data)
+{
+    PJ_UNUSED_ARG(data);
+    SDL_Quit();
+    return PJ_SUCCESS;
+}
+
+/* API: init factory */
+static pj_status_t sdl_factory_init(pjmedia_vid_dev_factory *f)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+    struct sdl_dev_info *ddi;
+    unsigned i, j;
+    pj_status_t status;
+    SDL_version version;
+
+    pj_list_init(&sf->streams);
+
+    status = job_queue_create(sf->pool, &sf->jq);
+    if (status != PJ_SUCCESS)
+        return PJMEDIA_EVID_INIT;
+
+    job_queue_post_job(sf->jq, sdl_init, NULL, 0, &status);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    status = pj_mutex_create_recursive(sf->pool, "sdl_factory",
+				       &sf->mutex);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_sem_create(sf->pool, NULL, 0, 1, &sf->sem);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create event handler thread. */
+    status = pj_thread_create(sf->pool, "sdl_thread", sdl_ev_thread,
+			      sf, 0, 0, &sf->sdl_thread);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    sf->dev_count = 1;
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    sf->dev_count++;
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+    sf->dev_info = (struct sdl_dev_info*)
+		   pj_pool_calloc(sf->pool, sf->dev_count,
+				  sizeof(struct sdl_dev_info));
+
+    ddi = &sf->dev_info[0];
+    pj_bzero(ddi, sizeof(*ddi));
+    strncpy(ddi->info.name, "SDL renderer", sizeof(ddi->info.name));
+    ddi->info.name[sizeof(ddi->info.name)-1] = '\0';
+    ddi->info.fmt_cnt = PJ_ARRAY_SIZE(sdl_fmts);
+
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    ddi = &sf->dev_info[OPENGL_DEV_IDX];
+    pj_bzero(ddi, sizeof(*ddi));
+    strncpy(ddi->info.name, "SDL openGL renderer", sizeof(ddi->info.name));
+    ddi->info.name[sizeof(ddi->info.name)-1] = '\0';
+    ddi->info.fmt_cnt = 1;
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+    for (i = 0; i < sf->dev_count; i++) {
+        ddi = &sf->dev_info[i];
+        strncpy(ddi->info.driver, "SDL", sizeof(ddi->info.driver));
+        ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
+        ddi->info.dir = PJMEDIA_DIR_RENDER;
+        ddi->info.has_callback = PJ_FALSE;
+        ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT |
+                         PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE;
+        ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
+        ddi->info.caps |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
+
+        for (j = 0; j < ddi->info.fmt_cnt; j++) {
+            pjmedia_format *fmt = &ddi->info.fmt[j];
+            pjmedia_format_init_video(fmt, sdl_fmts[j].fmt_id,
+                                      DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                      DEFAULT_FPS, 1);
+        }
+    }
+
+    SDL_VERSION(&version);
+    PJ_LOG(4, (THIS_FILE, "SDL %d.%d initialized",
+			  version.major, version.minor));
+
+    return PJ_SUCCESS;
+}
+
+/* API: destroy factory */
+static pj_status_t sdl_factory_destroy(pjmedia_vid_dev_factory *f)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+    pj_pool_t *pool = sf->pool;
+    pj_status_t status;
+
+    pj_assert(pj_list_empty(&sf->streams));
+
+    sf->is_quitting = PJ_TRUE;
+    if (sf->sdl_thread) {
+        pj_sem_post(sf->sem);
+#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
+        /* To prevent pj_thread_join() of getting stuck if we are in
+         * the main thread and we haven't finished processing the job
+         * posted by sdl_thread.
+         */
+        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
+#endif
+        pj_thread_join(sf->sdl_thread);
+        pj_thread_destroy(sf->sdl_thread);
+    }
+
+    if (sf->mutex) {
+	pj_mutex_destroy(sf->mutex);
+	sf->mutex = NULL;
+    }
+
+    if (sf->sem) {
+        pj_sem_destroy(sf->sem);
+        sf->sem = NULL;
+    }
+
+    job_queue_post_job(sf->jq, sdl_quit, NULL, 0, &status);
+    job_queue_destroy(sf->jq);
+
+    sf->pool = NULL;
+    pj_pool_release(pool);
+
+    return PJ_SUCCESS;
+}
+
+/* API: refresh the list of devices */
+static pj_status_t sdl_factory_refresh(pjmedia_vid_dev_factory *f)
+{
+    PJ_UNUSED_ARG(f);
+    return PJ_SUCCESS;
+}
+
+/* API: get number of devices */
+static unsigned sdl_factory_get_dev_count(pjmedia_vid_dev_factory *f)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+    return sf->dev_count;
+}
+
+/* API: get device info */
+static pj_status_t sdl_factory_get_dev_info(pjmedia_vid_dev_factory *f,
+					    unsigned index,
+					    pjmedia_vid_dev_info *info)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+
+    PJ_ASSERT_RETURN(index < sf->dev_count, PJMEDIA_EVID_INVDEV);
+
+    pj_memcpy(info, &sf->dev_info[index].info, sizeof(*info));
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default device parameter */
+static pj_status_t sdl_factory_default_param(pj_pool_t *pool,
+                                             pjmedia_vid_dev_factory *f,
+					     unsigned index,
+					     pjmedia_vid_dev_param *param)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+    struct sdl_dev_info *di = &sf->dev_info[index];
+
+    PJ_ASSERT_RETURN(index < sf->dev_count, PJMEDIA_EVID_INVDEV);
+    
+    PJ_UNUSED_ARG(pool);
+
+    pj_bzero(param, sizeof(*param));
+    param->dir = PJMEDIA_DIR_RENDER;
+    param->rend_id = index;
+    param->cap_id = PJMEDIA_VID_INVALID_DEV;
+
+    /* Set the device capabilities here */
+    param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
+    param->fmt.type = PJMEDIA_TYPE_VIDEO;
+    param->clock_rate = DEFAULT_CLOCK_RATE;
+    pj_memcpy(&param->fmt, &di->info.fmt[0], sizeof(param->fmt));
+
+    return PJ_SUCCESS;
+}
+
+static sdl_fmt_info* get_sdl_format_info(pjmedia_format_id id)
+{
+    unsigned i;
+
+    for (i = 0; i < sizeof(sdl_fmts)/sizeof(sdl_fmts[0]); i++) {
+        if (sdl_fmts[i].fmt_id == id)
+            return &sdl_fmts[i];
+    }
+
+    return NULL;
+}
+
+static pj_status_t sdl_destroy(void *data)
+{
+    struct sdl_stream *strm = (struct sdl_stream *)data;
+
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    if (strm->texture) {
+	glDeleteTextures(1, &strm->texture);
+	strm->texture = 0;
+    }
+    if (strm->gl_context) {
+        SDL_GL_DeleteContext(strm->gl_context);
+        strm->gl_context = NULL;
+    }
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+    if (strm->scr_tex) {
+        SDL_DestroyTexture(strm->scr_tex);
+        strm->scr_tex = NULL;
+    }
+    if (strm->renderer) {
+        SDL_DestroyRenderer(strm->renderer);
+        strm->renderer = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t sdl_destroy_all(void *data)
+{
+    struct sdl_stream *strm = (struct sdl_stream *)data;
+
+    sdl_destroy(data);
+#if !defined(TARGET_OS_IPHONE) || TARGET_OS_IPHONE == 0
+    if (strm->window &&
+        !(strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW))
+    {
+        SDL_DestroyWindow(strm->window);
+    }
+    strm->window = NULL;
+#endif /* TARGET_OS_IPHONE */
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t sdl_create_rend(struct sdl_stream * strm,
+                                   pjmedia_format *fmt)
+{
+    sdl_fmt_info *sdl_info;
+    const pjmedia_video_format_info *vfi;
+    pjmedia_video_format_detail *vfd;
+
+    sdl_info = get_sdl_format_info(fmt->id);
+    vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
+                                        fmt->id);
+    if (!vfi || !sdl_info)
+        return PJMEDIA_EVID_BADFORMAT;
+
+    strm->vafp.size = fmt->det.vid.size;
+    strm->vafp.buffer = NULL;
+    if (vfi->apply_fmt(vfi, &strm->vafp) != PJ_SUCCESS)
+        return PJMEDIA_EVID_BADFORMAT;
+
+    vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE);
+    strm->rect.x = strm->rect.y = 0;
+    strm->rect.w = (Uint16)vfd->size.w;
+    strm->rect.h = (Uint16)vfd->size.h;
+    if (strm->param.disp_size.w == 0)
+        strm->param.disp_size.w = strm->rect.w;
+    if (strm->param.disp_size.h == 0)
+        strm->param.disp_size.h = strm->rect.h;
+    strm->dstrect.x = strm->dstrect.y = 0;
+    strm->dstrect.w = (Uint16)strm->param.disp_size.w;
+    strm->dstrect.h = (Uint16)strm->param.disp_size.h;
+
+    sdl_destroy(strm);
+
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    if (strm->param.rend_id == OPENGL_DEV_IDX) {
+	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
+    }
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+    if (!strm->window) {
+        Uint32 flags = 0;
+        
+        if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS) {
+            if (!(strm->param.window_flags & PJMEDIA_VID_DEV_WND_BORDER))
+                flags |= SDL_WINDOW_BORDERLESS;
+            if (strm->param.window_flags & PJMEDIA_VID_DEV_WND_RESIZABLE)
+                flags |= SDL_WINDOW_RESIZABLE;
+        } else {
+            flags |= SDL_WINDOW_BORDERLESS;
+        }
+
+        if (!((strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) &&
+            strm->param.window_hide))
+        {
+            flags |= SDL_WINDOW_SHOWN;
+        } else {
+            flags &= ~SDL_WINDOW_SHOWN;
+            flags |= SDL_WINDOW_HIDDEN;
+        }
+
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+        if (strm->param.rend_id == OPENGL_DEV_IDX)
+            flags |= SDL_WINDOW_OPENGL;
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+        if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) {
+            /* Use the window supplied by the application. */
+	    strm->window = SDL_CreateWindowFrom(
+                               strm->param.window.info.window);
+	    if (!strm->window) {
+		sdl_log_err("SDL_CreateWindowFrom()");
+		return PJMEDIA_EVID_SYSERR;
+	    }
+        } else {
+            int x, y;
+
+            x = y = SDL_WINDOWPOS_CENTERED;
+            if (strm->param.flags & PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) {
+                x = strm->param.window_pos.x;
+                y = strm->param.window_pos.y;
+            }
+
+            /* Create the window where we will draw. */
+            strm->window = SDL_CreateWindow("pjmedia-SDL video",
+                                            x, y,
+                                            strm->param.disp_size.w,
+                                            strm->param.disp_size.h,
+                                            flags);
+	    if (!strm->window) {
+		sdl_log_err("SDL_CreateWindow()");
+		return PJMEDIA_EVID_SYSERR;
+	    }
+        }
+    }
+
+    /**
+      * We must call SDL_CreateRenderer in order for draw calls to
+      * affect this window.
+      */
+    strm->renderer = SDL_CreateRenderer(strm->window, -1, 0);
+    if (!strm->renderer) {
+	sdl_log_err("SDL_CreateRenderer()");
+        return PJMEDIA_EVID_SYSERR;
+    }
+
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    if (strm->param.rend_id == OPENGL_DEV_IDX) {
+        strm->gl_context = SDL_GL_CreateContext(strm->window);
+        if (!strm->gl_context) {
+            sdl_log_err("SDL_GL_CreateContext()");
+            return PJMEDIA_EVID_SYSERR;
+        }
+        SDL_GL_MakeCurrent(strm->window, strm->gl_context);
+
+        /* Init some OpenGL settings */
+	glDisable(GL_DEPTH_TEST);
+	glDisable(GL_CULL_FACE);
+	glEnable(GL_TEXTURE_2D);
+	
+	/* Init the viewport */
+	glViewport(0, 0, strm->param.disp_size.w, strm->param.disp_size.h);
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	
+	glOrtho(0.0, (GLdouble)strm->param.disp_size.w,
+                (GLdouble)strm->param.disp_size.h, 0.0, 0.0, 1.0);
+	
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+	
+	/* Create a texture */
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+	glGenTextures(1, &strm->texture);
+
+        if (!strm->texture)
+            return PJMEDIA_EVID_SYSERR;
+    } else
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+    {    
+        strm->scr_tex = SDL_CreateTexture(strm->renderer, sdl_info->sdl_format,
+                                          SDL_TEXTUREACCESS_STREAMING,
+                                          strm->rect.w, strm->rect.h);
+        if (strm->scr_tex == NULL) {
+            sdl_log_err("SDL_CreateTexture()");
+            return PJMEDIA_EVID_SYSERR;
+        }
+    
+        strm->pitch = strm->rect.w * SDL_BYTESPERPIXEL(sdl_info->sdl_format);
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t sdl_create(void *data)
+{
+    struct sdl_stream *strm = (struct sdl_stream *)data;
+    return sdl_create_rend(strm, &strm->param.fmt);
+}
+
+static pj_status_t resize_disp(struct sdl_stream *strm,
+                               pjmedia_rect_size *new_disp_size)
+{
+    pj_memcpy(&strm->param.disp_size, new_disp_size,
+              sizeof(strm->param.disp_size));
+    
+    if (strm->scr_tex) {
+        strm->dstrect.x = strm->dstrect.y = 0;
+        strm->dstrect.w = (Uint16)strm->param.disp_size.w;
+	strm->dstrect.h = (Uint16)strm->param.disp_size.h;
+	SDL_RenderSetViewport(strm->renderer, &strm->dstrect);
+    }
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    else if (strm->param.rend_id == OPENGL_DEV_IDX) {
+	sdl_create_rend(strm, &strm->param.fmt);
+    }
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t change_format(struct sdl_stream *strm,
+                                 pjmedia_format *new_fmt)
+{
+    pj_status_t status;
+
+    /* Recreate SDL renderer */
+    status = sdl_create_rend(strm, (new_fmt? new_fmt :
+				   &strm->param.fmt));
+    if (status == PJ_SUCCESS && new_fmt)
+        pjmedia_format_copy(&strm->param.fmt, new_fmt);
+
+    return status;
+}
+
+static pj_status_t put_frame(void *data)
+{
+    struct sdl_stream *stream = (struct sdl_stream *)data;
+    const pjmedia_frame *frame = stream->frame;
+
+    if (stream->scr_tex) {
+        SDL_UpdateTexture(stream->scr_tex, NULL, frame->buf, stream->pitch);
+        SDL_RenderClear(stream->renderer);
+        SDL_RenderCopy(stream->renderer, stream->scr_tex,
+		       &stream->rect, &stream->dstrect);
+        SDL_RenderPresent(stream->renderer);
+    }
+#if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+    else if (stream->param.rend_id == OPENGL_DEV_IDX && stream->texture) {
+	glBindTexture(GL_TEXTURE_2D, stream->texture);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+		     stream->rect.w, stream->rect.h, 0,
+		     GL_RGBA, GL_UNSIGNED_BYTE, frame->buf);
+	glBegin(GL_TRIANGLE_STRIP);
+	glTexCoord2f(0, 0); glVertex2i(0, 0);
+	glTexCoord2f(1, 0); glVertex2i(stream->param.disp_size.w, 0);
+	glTexCoord2f(0, 1); glVertex2i(0, stream->param.disp_size.h);
+	glTexCoord2f(1, 1);
+        glVertex2i(stream->param.disp_size.w, stream->param.disp_size.h);
+	glEnd();
+        SDL_GL_SwapWindow(stream->window);
+    }
+#endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+
+    return PJ_SUCCESS;
+}
+
+/* API: Put frame from stream */
+static pj_status_t sdl_stream_put_frame(pjmedia_vid_dev_stream *strm,
+					const pjmedia_frame *frame)
+{
+    struct sdl_stream *stream = (struct sdl_stream*)strm;
+    pj_status_t status;
+
+    stream->last_ts.u64 = frame->timestamp.u64;
+
+    if (!stream->is_running)
+	return PJ_EINVALIDOP;
+
+    if (frame->size==0 || frame->buf==NULL ||
+	frame->size < stream->vafp.framebytes)
+	return PJ_SUCCESS;
+
+    stream->frame = frame;
+    job_queue_post_job(stream->sf->jq, put_frame, strm, 0, &status);
+    
+    return status;
+}
+
+/* API: create stream */
+static pj_status_t sdl_factory_create_stream(
+					pjmedia_vid_dev_factory *f,
+					pjmedia_vid_dev_param *param,
+					const pjmedia_vid_dev_cb *cb,
+					void *user_data,
+					pjmedia_vid_dev_stream **p_vid_strm)
+{
+    struct sdl_factory *sf = (struct sdl_factory*)f;
+    pj_pool_t *pool;
+    struct sdl_stream *strm;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(param->dir == PJMEDIA_DIR_RENDER, PJ_EINVAL);
+
+    /* Create and Initialize stream descriptor */
+    pool = pj_pool_create(sf->pf, "sdl-dev", 1000, 1000, NULL);
+    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+
+    strm = PJ_POOL_ZALLOC_T(pool, struct sdl_stream);
+    pj_memcpy(&strm->param, param, sizeof(*param));
+    strm->pool = pool;
+    strm->sf = sf;
+    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
+    pj_list_init(&strm->list_entry);
+    strm->list_entry.stream = strm;
+    strm->user_data = user_data;
+
+    /* Create render stream here */
+    job_queue_post_job(sf->jq, sdl_create, strm, 0, &status);
+    if (status != PJ_SUCCESS) {
+        goto on_error;
+    }
+    pj_mutex_lock(strm->sf->mutex);
+    if (pj_list_empty(&strm->sf->streams))
+        pj_sem_post(strm->sf->sem);
+    pj_list_insert_after(&strm->sf->streams, &strm->list_entry);
+    pj_mutex_unlock(strm->sf->mutex);
+
+    /* Done */
+    strm->base.op = &stream_op;
+    *p_vid_strm = &strm->base;
+
+    return PJ_SUCCESS;
+
+on_error:
+    sdl_stream_destroy(&strm->base);
+    return status;
+}
+
+/* API: Get stream info. */
+static pj_status_t sdl_stream_get_param(pjmedia_vid_dev_stream *s,
+					pjmedia_vid_dev_param *pi)
+{
+    struct sdl_stream *strm = (struct sdl_stream*)s;
+
+    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &strm->param, sizeof(*pi));
+
+    if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW,
+			   &pi->window) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
+    }
+    if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION,
+			   &pi->window_pos) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION;
+    }
+    if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE,
+			   &pi->disp_size) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE;
+    }
+    if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE,
+			   &pi->window_hide) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE;
+    }
+    if (sdl_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS,
+			   &pi->window_flags) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS;
+    }
+
+    return PJ_SUCCESS;
+}
+
+struct strm_cap {
+    struct sdl_stream   *strm;
+    pjmedia_vid_dev_cap  cap;
+    union {
+        void            *pval;
+        const void      *cpval;
+    } pval;
+};
+
+static pj_status_t get_cap(void *data)
+{
+    struct strm_cap *scap = (struct strm_cap *)data;
+    struct sdl_stream *strm = scap->strm;
+    pjmedia_vid_dev_cap cap = scap->cap;
+    void *pval = scap->pval.pval;
+
+    if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW)
+    {
+	SDL_SysWMinfo info;
+	SDL_VERSION(&info.version);
+
+	if (SDL_GetWindowWMInfo(strm->window, &info)) {
+	    pjmedia_vid_dev_hwnd *wnd = (pjmedia_vid_dev_hwnd *)pval;
+	    if (0) { }
+#if defined(SDL_VIDEO_DRIVER_WINDOWS)
+	    else if (info.subsystem == SDL_SYSWM_WINDOWS) {
+		wnd->type = PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS;
+		wnd->info.win.hwnd = (void *)info.info.win.window;
+	    }
+#endif
+#if defined(SDL_VIDEO_DRIVER_X11)
+	    else if (info.subsystem == SDL_SYSWM_X11) {
+		wnd->info.x11.window = (void *)info.info.x11.window;
+		wnd->info.x11.display = (void *)info.info.x11.display;
+	    }
+#endif
+#if defined(SDL_VIDEO_DRIVER_COCOA)
+	    else if (info.subsystem == SDL_SYSWM_COCOA) {
+		wnd->info.cocoa.window = (void *)info.info.cocoa.window;
+	    }
+#endif
+#if defined(SDL_VIDEO_DRIVER_UIKIT)
+	    else if (info.subsystem == SDL_SYSWM_UIKIT) {
+		wnd->info.ios.window = (void *)info.info.uikit.window;
+	    }
+#endif
+	    else {
+		return PJMEDIA_EVID_INVCAP;
+	    }
+	    return PJ_SUCCESS;
+	} else
+	    return PJMEDIA_EVID_INVCAP;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) {
+        SDL_GetWindowPosition(strm->window, &((pjmedia_coord *)pval)->x,
+                              &((pjmedia_coord *)pval)->y);
+	return PJ_SUCCESS;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) {
+        SDL_GetWindowSize(strm->window, (int *)&((pjmedia_rect_size *)pval)->w,
+                          (int *)&((pjmedia_rect_size *)pval)->h);
+	return PJ_SUCCESS;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) {
+	Uint32 flag = SDL_GetWindowFlags(strm->window);
+	*((pj_bool_t *)pval) = (flag & SDL_WINDOW_HIDDEN)? PJ_TRUE: PJ_FALSE;
+	return PJ_SUCCESS;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS) {
+	Uint32 flag = SDL_GetWindowFlags(strm->window);
+        unsigned *wnd_flags = (unsigned *)pval;
+        if (!(flag & SDL_WINDOW_BORDERLESS))
+            *wnd_flags |= PJMEDIA_VID_DEV_WND_BORDER;
+        if (flag & SDL_WINDOW_RESIZABLE)
+            *wnd_flags |= PJMEDIA_VID_DEV_WND_RESIZABLE;
+	return PJ_SUCCESS;
+    }
+
+    return PJMEDIA_EVID_INVCAP;
+}
+
+/* API: get capability */
+static pj_status_t sdl_stream_get_cap(pjmedia_vid_dev_stream *s,
+				      pjmedia_vid_dev_cap cap,
+				      void *pval)
+{
+    struct sdl_stream *strm = (struct sdl_stream*)s;
+    struct strm_cap scap;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    scap.strm = strm;
+    scap.cap = cap;
+    scap.pval.pval = pval;
+
+    job_queue_post_job(strm->sf->jq, get_cap, &scap, 0, &status);
+
+    return status;
+}
+
+static pj_status_t set_cap(void *data)
+{
+    struct strm_cap *scap = (struct strm_cap *)data;
+    struct sdl_stream *strm = scap->strm;
+    pjmedia_vid_dev_cap cap = scap->cap;
+    const void *pval = scap->pval.cpval;
+
+    if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) {
+        /**
+         * Setting window's position when the window is hidden also sets
+         * the window's flag to shown (while the window is, actually,
+         * still hidden). This causes problems later when setting/querying
+         * the window's visibility.
+         * See ticket #1429 (http://trac.pjsip.org/repos/ticket/1429)
+         */
+	Uint32 flag = SDL_GetWindowFlags(strm->window);
+	if (flag & SDL_WINDOW_HIDDEN)
+            SDL_ShowWindow(strm->window);
+        SDL_SetWindowPosition(strm->window, ((pjmedia_coord *)pval)->x,
+                              ((pjmedia_coord *)pval)->y);
+	if (flag & SDL_WINDOW_HIDDEN)
+            SDL_HideWindow(strm->window);
+	return PJ_SUCCESS;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) {
+        if (*(pj_bool_t *)pval)
+            SDL_HideWindow(strm->window);
+        else
+            SDL_ShowWindow(strm->window);
+	return PJ_SUCCESS;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_FORMAT) {
+        pj_status_t status;
+
+        status = change_format(strm, (pjmedia_format *)pval);
+	if (status != PJ_SUCCESS) {
+	    pj_status_t status_;
+	    
+	    /**
+	     * Failed to change the output format. Try to revert
+	     * to its original format.
+	     */
+            status_ = change_format(strm, &strm->param.fmt);
+	    if (status_ != PJ_SUCCESS) {
+		/**
+		 * This means that we failed to revert to our
+		 * original state!
+		 */
+		status = PJMEDIA_EVID_ERR;
+	    }
+	}
+	
+	return status;
+    } else if (cap == PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) {
+	pjmedia_rect_size *new_size = (pjmedia_rect_size *)pval;
+
+	SDL_SetWindowSize(strm->window, new_size->w, new_size->h);
+        return resize_disp(strm, new_size);
+    }
+
+    return PJMEDIA_EVID_INVCAP;
+}
+
+/* API: set capability */
+static pj_status_t sdl_stream_set_cap(pjmedia_vid_dev_stream *s,
+				      pjmedia_vid_dev_cap cap,
+				      const void *pval)
+{
+    struct sdl_stream *strm = (struct sdl_stream*)s;
+    struct strm_cap scap;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    scap.strm = strm;
+    scap.cap = cap;
+    scap.pval.cpval = pval;
+
+    job_queue_post_job(strm->sf->jq, set_cap, &scap, 0, &status);
+
+    return status;
+}
+
+/* API: Start stream. */
+static pj_status_t sdl_stream_start(pjmedia_vid_dev_stream *strm)
+{
+    struct sdl_stream *stream = (struct sdl_stream*)strm;
+
+    PJ_LOG(4, (THIS_FILE, "Starting sdl video stream"));
+
+    stream->is_running = PJ_TRUE;
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: Stop stream. */
+static pj_status_t sdl_stream_stop(pjmedia_vid_dev_stream *strm)
+{
+    struct sdl_stream *stream = (struct sdl_stream*)strm;
+
+    PJ_LOG(4, (THIS_FILE, "Stopping sdl video stream"));
+
+    stream->is_running = PJ_FALSE;
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: Destroy stream. */
+static pj_status_t sdl_stream_destroy(pjmedia_vid_dev_stream *strm)
+{
+    struct sdl_stream *stream = (struct sdl_stream*)strm;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+    sdl_stream_stop(strm);
+
+    job_queue_post_job(stream->sf->jq, sdl_destroy_all, strm, 0, &status);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    pj_mutex_lock(stream->sf->mutex);
+    if (!pj_list_empty(&stream->list_entry))
+	pj_list_erase(&stream->list_entry);
+    pj_mutex_unlock(stream->sf->mutex);
+
+    pj_pool_release(stream->pool);
+
+    return PJ_SUCCESS;
+}
+
+/****************************************************************************
+ * Job queue implementation
+ */
+#if PJ_DARWINOS==0
+static int job_thread(void * data)
+{
+    job_queue *jq = (job_queue *)data;
+
+    while (1) {
+        job *jb;
+
+	/* Wait until there is a job. */
+        pj_sem_wait(jq->sem);
+
+        /* Make sure there is no pending jobs before we quit. */
+        if (jq->is_quitting && jq->head == jq->tail && !jq->is_full)
+            break;
+
+        jb = jq->jobs[jq->head];
+        jb->retval = (*jb->func)(jb->data);
+        /* If job queue is full and we already finish all the pending
+         * jobs, increase the size.
+         */
+        if (jq->is_full && ((jq->head + 1) % jq->size == jq->tail)) {
+            unsigned i, head;
+            pj_status_t status;
+
+            if (jq->old_sem) {
+                for (i = 0; i < jq->size / JOB_QUEUE_INC_FACTOR; i++) {
+                    pj_sem_destroy(jq->old_sem[i]);
+                }
+            }
+            jq->old_sem = jq->job_sem;
+
+            /* Double the job queue size. */
+            jq->size *= JOB_QUEUE_INC_FACTOR;
+            pj_sem_destroy(jq->sem);
+            status = pj_sem_create(jq->pool, "thread_sem", 0, jq->size + 1,
+                                   &jq->sem);
+            if (status != PJ_SUCCESS) {
+                PJ_LOG(3, (THIS_FILE, "Failed growing SDL job queue size."));
+                return 0;
+            }
+            jq->jobs = (job **)pj_pool_calloc(jq->pool, jq->size,
+                                              sizeof(job *));
+            jq->job_sem = (pj_sem_t **) pj_pool_calloc(jq->pool, jq->size,
+                                                       sizeof(pj_sem_t *));
+            for (i = 0; i < jq->size; i++) {
+                status = pj_sem_create(jq->pool, "job_sem", 0, 1,
+                                       &jq->job_sem[i]);
+                if (status != PJ_SUCCESS) {
+                    PJ_LOG(3, (THIS_FILE, "Failed growing SDL job "
+                                          "queue size."));
+                    return 0;
+                }
+            }
+            jq->is_full = PJ_FALSE;
+            head = jq->head;
+            jq->head = jq->tail = 0;
+            pj_sem_post(jq->old_sem[head]);
+        } else {
+            pj_sem_post(jq->job_sem[jq->head]);
+            jq->head = (jq->head + 1) % jq->size;
+        }
+    }
+
+    return 0;
+}
+#endif
+
+static pj_status_t job_queue_create(pj_pool_t *pool, job_queue **pjq)
+{
+    unsigned i;
+    pj_status_t status;
+
+    job_queue *jq = PJ_POOL_ZALLOC_T(pool, job_queue);
+    jq->pool = pool;
+    jq->size = INITIAL_MAX_JOBS;
+    status = pj_sem_create(pool, "thread_sem", 0, jq->size + 1, &jq->sem);
+    if (status != PJ_SUCCESS)
+        goto on_error;
+    jq->jobs = (job **)pj_pool_calloc(pool, jq->size, sizeof(job *));
+    jq->job_sem = (pj_sem_t **) pj_pool_calloc(pool, jq->size,
+                                               sizeof(pj_sem_t *));
+    for (i = 0; i < jq->size; i++) {
+        status = pj_sem_create(pool, "job_sem", 0, 1, &jq->job_sem[i]);
+        if (status != PJ_SUCCESS)
+            goto on_error;
+    }
+
+    status = pj_mutex_create_recursive(pool, "job_mutex", &jq->mutex);
+    if (status != PJ_SUCCESS)
+        goto on_error;
+
+#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
+    PJ_UNUSED_ARG(status);
+#else
+    status = pj_thread_create(pool, "job_th", job_thread, jq, 0, 0,
+                              &jq->thread);
+    if (status != PJ_SUCCESS)
+        goto on_error;
+#endif /* PJ_DARWINOS */
+
+    *pjq = jq;
+    return PJ_SUCCESS;
+
+on_error:
+    job_queue_destroy(jq);
+    return status;
+}
+
+static pj_status_t job_queue_post_job(job_queue *jq, job_func_ptr func,
+				      void *data, unsigned flags,
+				      pj_status_t *retval)
+{
+    job jb;
+    int tail;
+
+    if (jq->is_quitting)
+        return PJ_EBUSY;
+
+    jb.func = func;
+    jb.data = data;
+    jb.flags = flags;
+
+#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
+    PJ_UNUSED_ARG(tail);
+    NSAutoreleasePool *apool = [[NSAutoreleasePool alloc]init];
+    JQDelegate *jqd = [[JQDelegate alloc]init];
+    jqd->pjob = &jb;
+    [jqd performSelectorOnMainThread:@selector(run_job)
+ 	 withObject:nil waitUntilDone:YES];
+    [jqd release];
+    [apool release];
+#else /* PJ_DARWINOS */
+    pj_mutex_lock(jq->mutex);
+    jq->jobs[jq->tail] = &jb;
+    tail = jq->tail;
+    jq->tail = (jq->tail + 1) % jq->size;
+    if (jq->tail == jq->head) {
+	jq->is_full = PJ_TRUE;
+        PJ_LOG(4, (THIS_FILE, "SDL job queue is full, increasing "
+                              "the queue size."));
+        pj_sem_post(jq->sem);
+        /* Wait until our posted job is completed. */
+        pj_sem_wait(jq->job_sem[tail]);
+        pj_mutex_unlock(jq->mutex);
+    } else {
+        pj_mutex_unlock(jq->mutex);
+        pj_sem_post(jq->sem);
+        /* Wait until our posted job is completed. */
+        pj_sem_wait(jq->job_sem[tail]);
+    }
+#endif /* PJ_DARWINOS */
+
+    *retval = jb.retval;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t job_queue_destroy(job_queue *jq)
+{
+    unsigned i;
+
+    jq->is_quitting = PJ_TRUE;
+
+    if (jq->thread) {
+        pj_sem_post(jq->sem);
+        pj_thread_join(jq->thread);
+        pj_thread_destroy(jq->thread);
+    }
+
+    if (jq->sem) {
+        pj_sem_destroy(jq->sem);
+        jq->sem = NULL;
+    }
+    for (i = 0; i < jq->size; i++) {
+        if (jq->job_sem[i]) {
+            pj_sem_destroy(jq->job_sem[i]);
+            jq->job_sem[i] = NULL;
+        }
+    }
+    if (jq->old_sem) {
+        for (i = 0; i < jq->size / JOB_QUEUE_INC_FACTOR; i++) {
+            if (jq->old_sem[i]) {
+                pj_sem_destroy(jq->old_sem[i]);
+                jq->old_sem[i] = NULL;
+            }
+        }
+    }
+    if (jq->mutex) {
+        pj_mutex_destroy(jq->mutex);
+        jq->mutex = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+#ifdef _MSC_VER
+#   if defined(PJMEDIA_SDL_LIB)
+#	pragma comment( lib, PJMEDIA_SDL_LIB)
+#   elif SDL_VERSION_ATLEAST(2,0,0)
+#	pragma comment( lib, "sdl2.lib")
+#   elif SDL_VERSION_ATLEAST(1,3,0)
+#	pragma comment( lib, "sdl.lib")
+#   endif
+#   if PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL
+#	pragma comment(lib, "OpenGL32.lib")
+#   endif /* PJMEDIA_VIDEO_DEV_SDL_HAS_OPENGL */
+#endif /* _MSC_VER */
+
+
+#endif	/* PJMEDIA_VIDEO_DEV_HAS_SDL */
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef041af3567671b497e099d59ca33dbb4c8c2024.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef041af3567671b497e099d59ca33dbb4c8c2024.svn-base
new file mode 100644
index 0000000..d850301
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef041af3567671b497e099d59ca33dbb4c8c2024.svn-base
@@ -0,0 +1,982 @@
+/* $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 
+ */
+#ifndef __PJNATH_ICE_SESSION_H__
+#define __PJNATH_ICE_SESSION_H__
+
+/**
+ * @file ice_session.h
+ * @brief ICE session management
+ */
+#include <pjnath/types.h>
+#include <pjnath/stun_session.h>
+#include <pjnath/errno.h>
+#include <pj/sock.h>
+#include <pj/timer.h>
+
+PJ_BEGIN_DECL
+
+
+/**
+ * @addtogroup PJNATH_ICE_SESSION
+ * @{
+ *
+ * This module describes #pj_ice_sess, a transport independent ICE session,
+ * part of PJNATH - the Open Source NAT helper library.
+ *
+ * \section pj_ice_sess_sec ICE Session
+ *
+ * An ICE session, represented by #pj_ice_sess structure, is the lowest 
+ * abstraction of ICE in PJNATH, and it is used to perform and manage
+ * connectivity checks of transport address candidates <b>within a
+ * single media stream</b> (note: this differs from what is described
+ * in ICE draft, where an ICE session manages the whole media sessions
+ * rather than just a single stream).
+ *
+ * The ICE session described here is independent from any transports,
+ * meaning that the actual network I/O for this session would have to
+ * be performed by the application, or higher layer abstraction. 
+ * Using this framework, application would give any incoming packets to
+ * the ICE session, and it would provide the ICE session with a callback
+ * to send outgoing message.
+ *
+ * For higher abstraction of ICE where transport is included, please 
+ * see \ref PJNATH_ICE_STREAM_TRANSPORT.
+ *
+ * \subsection pj_ice_sess_using_sec Using The ICE Session
+ *
+ * The steps below describe how to use ICE session. Alternatively application
+ * can use the higher level ICE API, \ref PJNATH_ICE_STREAM_TRANSPORT,
+ * which has provided the integration of ICE with socket transport.
+ *
+ * The steps to use ICE session is similar for both offerer and
+ * answerer:
+ * - create ICE session with #pj_ice_sess_create(). Among other things,
+ *   application needs to specify:
+ *	- STUN configuration (pj_stun_config), containing STUN settings
+ *	  such as timeout values and the instances of timer heap and
+ *	  ioqueue.
+ *	- Session name, useful for identifying this session in the log.
+ *	- Initial ICE role (#pj_ice_sess_role). The role can be changed
+ *	  at later time with #pj_ice_sess_change_role(), and ICE session
+ *	  can also change its role automatically when it detects role
+ *	  conflict.
+ *	- Number of components in the media session.
+ *	- Callback to receive ICE events (#pj_ice_sess_cb)
+ *	- Optional local ICE username and password. If these arguments
+ *	  are NULL, they will be generated randomly.
+ * - Add local candidates for each component, with #pj_ice_sess_add_cand().
+ *   A candidate is represented with #pj_ice_sess_cand structure.
+ *   Each component must be provided with at least one candidate, and
+ *   all components must have the same number of candidates. Failing
+ *   to comply with this will cause failure during pairing process.
+ * - Create offer to describe local ICE candidates. ICE session does not
+ *   provide a function to create such offer, but application should be
+ *   able to create one since it knows about all components and candidates.
+ *   If application uses \ref PJNATH_ICE_STREAM_TRANSPORT, it can
+ *   enumerate local candidates by calling #pj_ice_strans_enum_cands().
+ *   Application may use #pj_ice_sess_find_default_cand() to let ICE
+ *   session chooses the default transport address to be used in SDP
+ *   c= and m= lines.
+ * - Send the offer to remote endpoint using signaling such as SIP.
+ * - Once application has received the answer, it should parse this
+ *   answer, build array of remote candidates, and create check lists by
+ *   calling #pj_ice_sess_create_check_list(). This process is known as
+ *   pairing the candidates, and will result in the creation of check lists.
+ * - Once checklist has been created, application then can call
+ *   #pj_ice_sess_start_check() to instruct ICE session to start
+ *   performing connectivity checks. The ICE session performs the
+ *   connectivity checks by processing each check in the checklists.
+ * - Application will be notified about the result of ICE connectivity
+ *   checks via the callback that was given in #pj_ice_sess_create()
+ *   above.
+ *
+ * To send data, application calls #pj_ice_sess_send_data(). If ICE
+ * negotiation has not completed, ICE session would simply drop the data,
+ * and return error to caller. If ICE negotiation has completed
+ * successfully, ICE session will in turn call the \a on_tx_pkt
+ * callback of #pj_ice_sess_cb instance that was previously registered
+ * in #pj_ice_sess_create() above.
+ *
+ * When application receives any packets on the underlying sockets, it
+ * must call #pj_ice_sess_on_rx_pkt(). The ICE session will inspect the
+ * packet to decide whether to process it locally (if the packet is a
+ * STUN message and is part of ICE session) or otherwise pass it back to
+ * application via \a on_rx_data callback.
+ */
+
+/**
+ * Forward declaration for checklist.
+ */
+typedef struct pj_ice_sess_checklist pj_ice_sess_checklist;
+
+/**
+ * This enumeration describes the type of an ICE candidate.
+ */
+typedef enum pj_ice_cand_type
+{
+    /**
+     * ICE host candidate. A host candidate represents the actual local
+     * transport address in the host.
+     */
+    PJ_ICE_CAND_TYPE_HOST,
+
+    /**
+     * ICE server reflexive candidate, which represents the public mapped
+     * address of the local address, and is obtained by sending STUN
+     * Binding request from the host candidate to a STUN server.
+     */
+    PJ_ICE_CAND_TYPE_SRFLX,
+
+    /**
+     * ICE peer reflexive candidate, which is the address as seen by peer
+     * agent during connectivity check.
+     */
+    PJ_ICE_CAND_TYPE_PRFLX,
+
+    /**
+     * ICE relayed candidate, which represents the address allocated in
+     * TURN server.
+     */
+    PJ_ICE_CAND_TYPE_RELAYED,
+
+    /**
+     * Number of defined ICE candidate types.
+     */
+    PJ_ICE_CAND_TYPE_MAX
+
+} pj_ice_cand_type;
+
+
+/** Forward declaration for pj_ice_sess */
+typedef struct pj_ice_sess pj_ice_sess;
+
+/** Forward declaration for pj_ice_sess_check */
+typedef struct pj_ice_sess_check pj_ice_sess_check;
+
+
+/**
+ * This structure describes ICE component. 
+ * A media stream may require multiple components, each of which has 
+ * to work for the media stream as a whole to work.  For media streams
+ * based on RTP, there are two components per media stream - one for RTP,
+ * and one for RTCP.
+ */
+typedef struct pj_ice_sess_comp
+{
+    /**
+     * Pointer to ICE check with highest priority which connectivity check
+     * has been successful. The value will be NULL if a no successful check
+     * has not been found for this component.
+     */
+    pj_ice_sess_check	*valid_check;
+
+    /**
+     * Pointer to ICE check with highest priority which connectivity check
+     * has been successful and it has been nominated. The value may be NULL
+     * if there is no such check yet.
+     */
+    pj_ice_sess_check	*nominated_check;
+
+    /**
+     * The STUN session to be used to send and receive STUN messages for this
+     * component.
+     */
+    pj_stun_session	*stun_sess;
+
+} pj_ice_sess_comp;
+
+
+/**
+ * Data structure to be attached to internal message processing.
+ */
+typedef struct pj_ice_msg_data
+{
+    /** Transport ID for this message */
+    unsigned	transport_id;
+
+    /** Flag to indicate whether data.req contains data */
+    pj_bool_t	has_req_data;
+
+    /** The data */
+    union data {
+	/** Request data */
+	struct request_data {
+	    pj_ice_sess		    *ice;   /**< ICE session	*/
+	    pj_ice_sess_checklist   *clist; /**< Checklist	*/
+	    unsigned		     ckid;  /**< Check ID	*/
+	} req;
+    } data;
+
+} pj_ice_msg_data;
+
+
+/**
+ * This structure describes an ICE candidate.
+ * ICE candidate is a transport address that is to be tested by ICE
+ * procedures in order to determine its suitability for usage for
+ * receipt of media.  Candidates also have properties - their type
+ * (server reflexive, relayed or host), priority, foundation, and
+ * base.
+ */
+typedef struct pj_ice_sess_cand
+{
+    /**
+     * The candidate type, as described in #pj_ice_cand_type enumeration.
+     */
+    pj_ice_cand_type	 type;
+
+    /** 
+     * Status of this candidate. The value will be PJ_SUCCESS if candidate
+     * address has been resolved successfully, PJ_EPENDING when the address
+     * resolution process is in progress, or other value when the address 
+     * resolution has completed with failure.
+     */
+    pj_status_t		 status;
+
+    /**
+     * The component ID of this candidate. Note that component IDs starts
+     * with one for RTP and two for RTCP. In other words, it's not zero
+     * based.
+     */
+    pj_uint8_t		 comp_id;
+
+    /**
+     * Transport ID to be used to send packets for this candidate.
+     */
+    pj_uint8_t		 transport_id;
+
+    /**
+     * Local preference value, which typically is 65535.
+     */
+    pj_uint16_t		 local_pref;
+
+    /**
+     * The foundation string, which is an identifier which value will be
+     * equivalent for two candidates that are of the same type, share the 
+     * same base, and come from the same STUN server. The foundation is 
+     * used to optimize ICE performance in the Frozen algorithm.
+     */
+    pj_str_t		 foundation;
+
+    /**
+     * The candidate's priority, a 32-bit unsigned value which value will be
+     * calculated by the ICE session when a candidate is registered to the
+     * ICE session.
+     */
+    pj_uint32_t		 prio;
+
+    /**
+     * IP address of this candidate. For host candidates, this represents
+     * the local address of the socket. For reflexive candidates, the value
+     * will be the public address allocated in NAT router for the host
+     * candidate and as reported in MAPPED-ADDRESS or XOR-MAPPED-ADDRESS
+     * attribute of STUN Binding request. For relayed candidate, the value 
+     * will be the address allocated in the TURN server by STUN Allocate
+     * request.
+     */
+    pj_sockaddr		 addr;
+
+    /**
+     * Base address of this candidate. "Base" refers to the address an agent 
+     * sends from for a particular candidate.  For host candidates, the base
+     * is the same as the host candidate itself. For reflexive candidates, 
+     * the base is the local IP address of the socket. For relayed candidates,
+     * the base address is the transport address allocated in the TURN server
+     * for this candidate.
+     */
+    pj_sockaddr		 base_addr;
+
+    /**
+     * Related address, which is used for informational only and is not used
+     * in any way by the ICE session.
+     */
+    pj_sockaddr		 rel_addr;
+
+} pj_ice_sess_cand;
+
+
+/**
+ * This enumeration describes the state of ICE check.
+ */
+typedef enum pj_ice_sess_check_state
+{
+    /**
+     * A check for this pair hasn't been performed, and it can't
+     * yet be performed until some other check succeeds, allowing this
+     * pair to unfreeze and move into the Waiting state.
+     */
+    PJ_ICE_SESS_CHECK_STATE_FROZEN,
+
+    /**
+     * A check has not been performed for this pair, and can be
+     * performed as soon as it is the highest priority Waiting pair on
+     * the check list.
+     */
+    PJ_ICE_SESS_CHECK_STATE_WAITING,
+
+    /**
+     * A check has not been performed for this pair, and can be
+     * performed as soon as it is the highest priority Waiting pair on
+     * the check list.
+     */
+    PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS,
+
+    /**
+     * A check has not been performed for this pair, and can be
+     * performed as soon as it is the highest priority Waiting pair on
+     * the check list.
+     */
+    PJ_ICE_SESS_CHECK_STATE_SUCCEEDED,
+
+    /**
+     * A check for this pair was already done and failed, either
+     * never producing any response or producing an unrecoverable failure
+     * response.
+     */
+    PJ_ICE_SESS_CHECK_STATE_FAILED
+
+} pj_ice_sess_check_state;
+
+
+/**
+ * This structure describes an ICE connectivity check. An ICE check
+ * contains a candidate pair, and will involve sending STUN Binding 
+ * Request transaction for the purposes of verifying connectivity. 
+ * A check is sent from the local candidate to the remote candidate 
+ * of a candidate pair.
+ */
+struct pj_ice_sess_check
+{
+    /**
+     * Pointer to local candidate entry of this check.
+     */
+    pj_ice_sess_cand	*lcand;
+
+    /**
+     * Pointer to remote candidate entry of this check.
+     */
+    pj_ice_sess_cand	*rcand;
+
+    /**
+     * Check priority.
+     */
+    pj_timestamp	 prio;
+
+    /**
+     * Connectivity check state.
+     */
+    pj_ice_sess_check_state	 state;
+
+    /**
+     * STUN transmit data containing STUN Binding request that was sent 
+     * as part of this check. The value will only be set when this check 
+     * has a pending transaction, and is used to cancel the transaction
+     * when other check has succeeded.
+     */
+    pj_stun_tx_data	*tdata;
+
+    /**
+     * Flag to indicate whether this check is nominated. A nominated check
+     * contains USE-CANDIDATE attribute in its STUN Binding request.
+     */
+    pj_bool_t		 nominated;
+
+    /**
+     * When the check failed, this will contain the failure status of the
+     * STUN transaction.
+     */
+    pj_status_t		 err_code;
+};
+
+
+/**
+ * This enumeration describes ICE checklist state.
+ */
+typedef enum pj_ice_sess_checklist_state
+{
+    /**
+     * The checklist is not yet running.
+     */
+    PJ_ICE_SESS_CHECKLIST_ST_IDLE,
+
+    /**
+     * In this state, ICE checks are still in progress for this
+     * media stream.
+     */
+    PJ_ICE_SESS_CHECKLIST_ST_RUNNING,
+
+    /**
+     * In this state, ICE checks have completed for this media stream,
+     * either successfully or with failure.
+     */
+    PJ_ICE_SESS_CHECKLIST_ST_COMPLETED
+
+} pj_ice_sess_checklist_state;
+
+
+/**
+ * This structure represents ICE check list, that is an ordered set of 
+ * candidate pairs that an agent will use to generate checks.
+ */
+struct pj_ice_sess_checklist
+{
+    /**
+     * The checklist state.
+     */
+    pj_ice_sess_checklist_state   state;
+
+    /**
+     * Number of candidate pairs (checks).
+     */
+    unsigned		     count;
+
+    /**
+     * Array of candidate pairs (checks).
+     */
+    pj_ice_sess_check	     checks[PJ_ICE_MAX_CHECKS];
+
+    /**
+     * A timer used to perform periodic check for this checklist.
+     */
+    pj_timer_entry	     timer;
+
+};
+
+
+/**
+ * This structure contains callbacks that will be called by the ICE
+ * session.
+ */
+typedef struct pj_ice_sess_cb
+{
+    /**
+     * An optional callback that will be called by the ICE session when
+     * ICE negotiation has completed, successfully or with failure.
+     *
+     * @param ice	    The ICE session.
+     * @param status	    Will contain PJ_SUCCESS if ICE negotiation is
+     *			    successful, or some error code.
+     */
+    void	(*on_ice_complete)(pj_ice_sess *ice, pj_status_t status);
+
+    /**
+     * A mandatory callback which will be called by the ICE session when
+     * it needs to send outgoing STUN packet. 
+     *
+     * @param ice	    The ICE session.
+     * @param comp_id	    ICE component ID.
+     * @param transport_id  Transport ID.
+     * @param pkt	    The STUN packet.
+     * @param size	    The size of the packet.
+     * @param dst_addr	    Packet destination address.
+     * @param dst_addr_len  Length of destination address.
+     */
+    pj_status_t (*on_tx_pkt)(pj_ice_sess *ice, unsigned comp_id, 
+			     unsigned transport_id,
+			     const void *pkt, pj_size_t size,
+			     const pj_sockaddr_t *dst_addr,
+			     unsigned dst_addr_len);
+
+    /**
+     * A mandatory callback which will be called by the ICE session when
+     * it receives packet which is not part of ICE negotiation.
+     *
+     * @param ice	    The ICE session.
+     * @param comp_id	    ICE component ID.
+     * @param transport_id  Transport ID.
+     * @param pkt	    The whole packet.
+     * @param size	    Size of the packet.
+     * @param src_addr	    Source address where this packet was received 
+     *			    from.
+     * @param src_addr_len  The length of source address.
+     */
+    void	(*on_rx_data)(pj_ice_sess *ice, unsigned comp_id,
+			      unsigned transport_id, 
+			      void *pkt, pj_size_t size,
+			      const pj_sockaddr_t *src_addr,
+			      unsigned src_addr_len);
+} pj_ice_sess_cb;
+
+
+/**
+ * This enumeration describes the role of the ICE agent.
+ */
+typedef enum pj_ice_sess_role
+{
+    /**
+     * The role is unknown.
+     */
+    PJ_ICE_SESS_ROLE_UNKNOWN,
+
+    /**
+     * The ICE agent is in controlled role.
+     */
+    PJ_ICE_SESS_ROLE_CONTROLLED,
+
+    /**
+     * The ICE agent is in controlling role.
+     */
+    PJ_ICE_SESS_ROLE_CONTROLLING
+
+} pj_ice_sess_role;
+
+
+/**
+ * This structure represents an incoming check (an incoming Binding
+ * request message), and is mainly used to keep early checks in the
+ * list in the ICE session. An early check is a request received
+ * from remote when we haven't received SDP answer yet, therefore we
+ * can't perform triggered check. For such cases, keep the incoming
+ * request in a list, and we'll do triggered checks (simultaneously)
+ * as soon as we receive answer.
+ */
+typedef struct pj_ice_rx_check
+{
+    PJ_DECL_LIST_MEMBER(struct pj_ice_rx_check); /**< Standard list     */
+
+    unsigned		 comp_id;	/**< Component ID.		*/
+    unsigned		 transport_id;	/**< Transport ID.		*/
+
+    pj_sockaddr		 src_addr;	/**< Source address of request	*/
+    unsigned		 src_addr_len;	/**< Length of src address.	*/
+
+    pj_bool_t		 use_candidate;	/**< USE-CANDIDATE is present?	*/
+    pj_uint32_t		 priority;	/**< PRIORITY value in the req.	*/
+    pj_stun_uint64_attr *role_attr;	/**< ICE-CONTROLLING/CONTROLLED	*/
+
+} pj_ice_rx_check;
+
+
+/**
+ * This structure describes various ICE session options. Application
+ * configure the ICE session with these options by calling 
+ * #pj_ice_sess_set_options().
+ */
+typedef struct pj_ice_sess_options
+{
+    /**
+     * Specify whether to use aggressive nomination.
+     */
+    pj_bool_t		aggressive;
+
+    /**
+     * For controlling agent if it uses regular nomination, specify the delay
+     * to perform nominated check (connectivity check with USE-CANDIDATE 
+     * attribute) after all components have a valid pair.
+     *
+     * Default value is PJ_ICE_NOMINATED_CHECK_DELAY.
+     */
+    unsigned		nominated_check_delay;
+
+    /**
+     * For a controlled agent, specify how long it wants to wait (in 
+     * milliseconds) for the controlling agent to complete sending 
+     * connectivity check with nominated flag set to true for all components
+     * after the controlled agent has found that all connectivity checks in
+     * its checklist have been completed and there is at least one successful
+     * (but not nominated) check for every component.
+     *
+     * Default value for this option is 
+     * ICE_CONTROLLED_AGENT_WAIT_NOMINATION_TIMEOUT. Specify -1 to disable
+     * this timer.
+     */
+    int			controlled_agent_want_nom_timeout;
+
+} pj_ice_sess_options;
+
+
+/**
+ * This structure describes the ICE session. For this version of PJNATH,
+ * an ICE session corresponds to a single media stream (unlike the ICE
+ * session described in the ICE standard where an ICE session covers the
+ * whole media and may consist of multiple media streams). The decision
+ * to support only a single media session was chosen for simplicity,
+ * while still allowing application to utilize multiple media streams by
+ * creating multiple ICE sessions, one for each media stream.
+ */
+struct pj_ice_sess
+{
+    char		obj_name[PJ_MAX_OBJ_NAME];  /**< Object name.	    */
+
+    pj_pool_t		*pool;			    /**< Pool instance.	    */
+    void		*user_data;		    /**< App. data.	    */
+    pj_grp_lock_t	*grp_lock;		    /**< Group lock	    */
+    pj_ice_sess_role	 role;			    /**< ICE role.	    */
+    pj_ice_sess_options	 opt;			    /**< Options	    */
+    pj_timestamp	 tie_breaker;		    /**< Tie breaker value  */
+    pj_uint8_t		*prefs;			    /**< Type preference.   */
+    pj_bool_t		 is_nominating;		    /**< Nominating stage   */
+    pj_bool_t		 is_complete;		    /**< Complete?	    */
+    pj_bool_t		 is_destroying;		    /**< Destroy is called  */
+    pj_status_t		 ice_status;		    /**< Error status.	    */
+    pj_timer_entry	 timer;			    /**< ICE timer.	    */
+    pj_ice_sess_cb	 cb;			    /**< Callback.	    */
+
+    pj_stun_config	 stun_cfg;		    /**< STUN settings.	    */
+
+    /* STUN credentials */
+    pj_str_t		 tx_ufrag;		    /**< Remote ufrag.	    */
+    pj_str_t		 tx_uname;		    /**< Uname for TX.	    */
+    pj_str_t		 tx_pass;		    /**< Remote password.   */
+    pj_str_t		 rx_ufrag;		    /**< Local ufrag.	    */
+    pj_str_t		 rx_uname;		    /**< Uname for RX	    */
+    pj_str_t		 rx_pass;		    /**< Local password.    */
+
+    /* Components */
+    unsigned		 comp_cnt;		    /**< # of components.   */
+    pj_ice_sess_comp	 comp[PJ_ICE_MAX_COMP];	    /**< Component array    */
+    unsigned		 comp_ka;		    /**< Next comp for KA   */
+
+    /* Local candidates */
+    unsigned		 lcand_cnt;		    /**< # of local cand.   */
+    pj_ice_sess_cand	 lcand[PJ_ICE_MAX_CAND];    /**< Array of cand.	    */
+
+    /* Remote candidates */
+    unsigned		 rcand_cnt;		    /**< # of remote cand.  */
+    pj_ice_sess_cand	 rcand[PJ_ICE_MAX_CAND];    /**< Array of cand.	    */
+
+    /** Array of transport datas */
+    pj_ice_msg_data	 tp_data[4];
+
+    /* List of eearly checks */
+    pj_ice_rx_check	 early_check;		    /**< Early checks.	    */
+
+    /* Checklist */
+    pj_ice_sess_checklist clist;		    /**< Active checklist   */
+    
+    /* Valid list */
+    pj_ice_sess_checklist valid_list;		    /**< Valid list.	    */
+    
+    /** Temporary buffer for misc stuffs to avoid using stack too much */
+    union {
+    	char txt[128];
+	char errmsg[PJ_ERR_MSG_SIZE];
+    } tmp;
+};
+
+
+/**
+ * This is a utility function to retrieve the string name for the
+ * particular candidate type.
+ *
+ * @param type		Candidate type.
+ *
+ * @return		The string representation of the candidate type.
+ */
+PJ_DECL(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type);
+
+
+/**
+ * This is a utility function to retrieve the string name for the
+ * particular role type.
+ *
+ * @param role		Role type.
+ *
+ * @return		The string representation of the role.
+ */
+PJ_DECL(const char*) pj_ice_sess_role_name(pj_ice_sess_role role);
+
+
+/**
+ * This is a utility function to calculate the foundation identification
+ * for a candidate.
+ *
+ * @param pool		Pool to allocate the foundation string.
+ * @param foundation	Pointer to receive the foundation string.
+ * @param type		Candidate type.
+ * @param base_addr	Base address of the candidate.
+ */
+PJ_DECL(void) pj_ice_calc_foundation(pj_pool_t *pool,
+				     pj_str_t *foundation,
+				     pj_ice_cand_type type,
+				     const pj_sockaddr *base_addr);
+
+/**
+ * Initialize ICE session options with library default values.
+ *
+ * @param opt		ICE session options.
+ */
+PJ_DECL(void) pj_ice_sess_options_default(pj_ice_sess_options *opt);
+
+/**
+ * Create ICE session with the specified role and number of components.
+ * Application would typically need to create an ICE session before
+ * sending an offer or upon receiving one. After the session is created,
+ * application can register candidates to the ICE session by calling
+ * #pj_ice_sess_add_cand() function.
+ *
+ * @param stun_cfg	The STUN configuration settings, containing among
+ *			other things the timer heap instance to be used
+ *			by the ICE session.
+ * @param name		Optional name to identify this ICE instance in
+ *			the log file.
+ * @param role		ICE role.
+ * @param comp_cnt	Number of components.
+ * @param cb		ICE callback.
+ * @param local_ufrag	Optional string to be used as local username to
+ *			authenticate incoming STUN binding request. If
+ *			the value is NULL, a random string will be 
+ *			generated.
+ * @param local_passwd	Optional string to be used as local password.
+ * @param grp_lock	Optional group lock to be used by this session.
+ * 			If NULL, the session will create one itself.
+ * @param p_ice		Pointer to receive the ICE session instance.
+ *
+ * @return		PJ_SUCCESS if ICE session is created successfully.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
+				        const char *name,
+				        pj_ice_sess_role role,
+				        unsigned comp_cnt,
+				        const pj_ice_sess_cb *cb,
+				        const pj_str_t *local_ufrag,
+				        const pj_str_t *local_passwd,
+				        pj_grp_lock_t *grp_lock,
+				        pj_ice_sess **p_ice);
+
+/**
+ * Get the value of various options of the ICE session.
+ *
+ * @param ice		The ICE session.
+ * @param opt		The options to be initialized with the values
+ *			from the ICE session.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_get_options(pj_ice_sess *ice,
+					     pj_ice_sess_options *opt);
+
+/**
+ * Specify various options for this ICE session. Application MUST only
+ * call this function after the ICE session has been created but before
+ * any connectivity check is started.
+ *
+ * Application should call #pj_ice_sess_get_options() to initialize the
+ * options with their default values.
+ *
+ * @param ice		The ICE session.
+ * @param opt		Options to be applied to the ICE session.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice,
+					     const pj_ice_sess_options *opt);
+
+/**
+ * Destroy ICE session. This will cancel any connectivity checks currently
+ * running, if any, and any other events scheduled by this session, as well
+ * as all memory resources.
+ *
+ * @param ice		ICE session instance.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_destroy(pj_ice_sess *ice);
+
+
+/**
+ * Change session role. This happens for example when ICE session was
+ * created with controlled role when receiving an offer, but it turns out
+ * that the offer contains "a=ice-lite" attribute when the SDP gets
+ * inspected.
+ *
+ * @param ice		The ICE session.
+ * @param new_role	The new role to be set.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice,
+					     pj_ice_sess_role new_role);
+
+
+/**
+ * Assign a custom preference values for ICE candidate types. By assigning
+ * custom preference value, application can control the order of candidates
+ * to be checked first. The default preference settings is to use 126 for 
+ * host candidates, 100 for server reflexive candidates, 110 for peer 
+ * reflexive candidates, an 0 for relayed candidates.
+ *
+ * Note that this function must be called before any candidates are added
+ * to the ICE session.
+ *
+ * @param ice		The ICE session.
+ * @param prefs		Array of candidate preference value. The values are
+ *			put in the array indexed by the candidate type as
+ *			specified in pj_ice_cand_type.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+					   const pj_uint8_t prefs[4]);
+
+
+
+/**
+ * Add a candidate to this ICE session. Application must add candidates for
+ * each components ID before it can start pairing the candidates and 
+ * performing connectivity checks.
+ *
+ * @param ice		ICE session instance.
+ * @param comp_id	Component ID of this candidate.
+ * @param transport_id	Transport ID to be used to send packets for this
+ *			candidate.
+ * @param type		Candidate type.
+ * @param local_pref	Local preference for this candidate, which
+ *			normally should be set to 65535.
+ * @param foundation	Foundation identification.
+ * @param addr		The candidate address.
+ * @param base_addr	The candidate's base address.
+ * @param rel_addr	Optional related address.
+ * @param addr_len	Length of addresses.
+ * @param p_cand_id	Optional pointer to receive the candidate ID.
+ *
+ * @return		PJ_SUCCESS if candidate is successfully added.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
+					  unsigned comp_id,
+					  unsigned transport_id,
+					  pj_ice_cand_type type,
+					  pj_uint16_t local_pref,
+					  const pj_str_t *foundation,
+					  const pj_sockaddr_t *addr,
+					  const pj_sockaddr_t *base_addr,
+					  const pj_sockaddr_t *rel_addr,
+					  int addr_len,
+					  unsigned *p_cand_id);
+
+/**
+ * Find default candidate for the specified component ID, using this
+ * rule:
+ *  - if the component has a successful candidate pair, then the
+ *    local candidate of this pair will be returned.
+ *  - otherwise a relay, reflexive, or host candidate will be selected 
+ *    on that specified order.
+ *
+ * @param ice		The ICE session instance.
+ * @param comp_id	The component ID.
+ * @param p_cand_id	Pointer to receive the candidate ID.
+ *
+ * @return		PJ_SUCCESS if a candidate has been selected.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
+						   unsigned comp_id,
+						   int *p_cand_id);
+
+/**
+ * Pair the local and remote candidates to create check list. Application
+ * typically would call this function after receiving SDP containing ICE
+ * candidates from the remote host (either upon receiving the initial
+ * offer, for UAS, or upon receiving the answer, for UAC).
+ *
+ * Note that ICE connectivity check will not start until application calls
+ * #pj_ice_sess_start_check().
+ *
+ * @param ice		ICE session instance.
+ * @param rem_ufrag	Remote ufrag, as seen in the SDP received from 
+ *			the remote agent.
+ * @param rem_passwd	Remote password, as seen in the SDP received from
+ *			the remote agent.
+ * @param rem_cand_cnt	Number of remote candidates.
+ * @param rem_cand	Remote candidate array. Remote candidates are
+ *			gathered from the SDP received from the remote 
+ *			agent.
+ *
+ * @return		PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) 
+pj_ice_sess_create_check_list(pj_ice_sess *ice,
+			      const pj_str_t *rem_ufrag,
+			      const pj_str_t *rem_passwd,
+			      unsigned rem_cand_cnt,
+			      const pj_ice_sess_cand rem_cand[]);
+
+/**
+ * Start ICE periodic check. This function will return immediately, and
+ * application will be notified about the connectivity check status in
+ * #pj_ice_sess_cb callback.
+ *
+ * @param ice		The ICE session instance.
+ *
+ * @return		PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice);
+
+
+/**
+ * Send data using this ICE session. If ICE checks have not produced a
+ * valid check for the specified component ID, this function will return
+ * with failure. Otherwise ICE session will send the packet to remote
+ * destination using the nominated local candidate for the specified
+ * component.
+ *
+ * This function will in turn call \a on_tx_pkt function in
+ * #pj_ice_sess_cb callback to actually send the packet to the wire.
+ *
+ * @param ice		The ICE session.
+ * @param comp_id	Component ID.
+ * @param data		The data or packet to be sent.
+ * @param data_len	Size of data or packet, in bytes.
+ *
+ * @return		PJ_SUCCESS if data is sent successfully.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice,
+					   unsigned comp_id,
+					   const void *data,
+					   pj_size_t data_len);
+
+/**
+ * Report the arrival of packet to the ICE session. Since ICE session
+ * itself doesn't have any transports, it relies on application or
+ * higher layer component to give incoming packets to the ICE session.
+ * If the packet is not a STUN packet, this packet will be given back
+ * to application via \a on_rx_data() callback in #pj_ice_sess_cb.
+ *
+ * @param ice		The ICE session.
+ * @param comp_id	Component ID.
+ * @param transport_id	Number to identify where this packet was received
+ *			from. This parameter will be returned back to
+ *			application in \a on_tx_pkt() callback.
+ * @param pkt		Incoming packet.
+ * @param pkt_size	Size of incoming packet.
+ * @param src_addr	Source address of the packet.
+ * @param src_addr_len	Length of the address.
+ *
+ * @return		PJ_SUCCESS or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
+					   unsigned comp_id,
+					   unsigned transport_id,
+					   void *pkt,
+					   pj_size_t pkt_size,
+					   const pj_sockaddr_t *src_addr,
+					   int src_addr_len);
+
+
+
+/**
+ * @}
+ */
+
+
+PJ_END_DECL
+
+
+#endif	/* __PJNATH_ICE_SESSION_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef0cadecb743f8a4c1a92af0df0e7182de41ca44.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef0cadecb743f8a4c1a92af0df0e7182de41ca44.svn-base
new file mode 100644
index 0000000..ec32c6e
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef0cadecb743f8a4c1a92af0df0e7182de41ca44.svn-base
@@ -0,0 +1,508 @@
+/* Copyright (C) 2005 Jean-Marc Valin, CSIRO, Christopher Montgomery
+   File: vorbis_psy.c
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+   
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+   
+   - Neither the name of the Xiph.org Foundation nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+   
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef VORBIS_PSYCHO
+
+#include "arch.h"
+#include "smallft.h"
+#include "lpc.h"
+#include "vorbis_psy.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+/* psychoacoustic setup ********************************************/
+
+static VorbisPsyInfo example_tuning = {
+  
+  .5,.5,  
+  3,3,25,
+  
+  /*63     125     250     500      1k      2k      4k      8k     16k*/
+  // vorbis mode 4 style
+  //{-32,-32,-32,-32,-28,-24,-22,-20,-20, -20, -20, -8, -6, -6, -6, -6, -6},
+  { -4, -6, -6, -6, -6, -6, -6, -6, -8, -8,-10,-10, -8, -6, -4, -4, -2},
+  
+  {
+    0, 1, 2, 3, 4, 5, 5,  5,     /* 7dB */
+    6, 6, 6, 5, 4, 4, 4,  4,     /* 15dB */
+    4, 4, 5, 5, 5, 6, 6,  6,     /* 23dB */
+    7, 7, 7, 8, 8, 8, 9, 10,     /* 31dB */
+    11,12,13,14,15,16,17, 18,     /* 39dB */
+  }
+
+};
+
+
+
+/* there was no great place to put this.... */
+#include <stdio.h>
+static void _analysis_output(char *base,int i,float *v,int n,int bark,int dB){
+  int j;
+  FILE *of;
+  char buffer[80];
+
+  sprintf(buffer,"%s_%d.m",base,i);
+  of=fopen(buffer,"w");
+  
+  if(!of)perror("failed to open data dump file");
+  
+  for(j=0;j<n;j++){
+    if(bark){
+      float b=toBARK((4000.f*j/n)+.25);
+      fprintf(of,"%f ",b);
+    }else
+      fprintf(of,"%f ",(double)j);
+    
+    if(dB){
+      float val;
+      if(v[j]==0.)
+	val=-140.;
+      else
+	val=todB(v[j]);
+      fprintf(of,"%f\n",val);
+    }else{
+      fprintf(of,"%f\n",v[j]);
+    }
+  }
+  fclose(of);
+}
+
+static void bark_noise_hybridmp(int n,const long *b,
+                                const float *f,
+                                float *noise,
+                                const float offset,
+                                const int fixed){
+  
+  float *N=alloca(n*sizeof(*N));
+  float *X=alloca(n*sizeof(*N));
+  float *XX=alloca(n*sizeof(*N));
+  float *Y=alloca(n*sizeof(*N));
+  float *XY=alloca(n*sizeof(*N));
+
+  float tN, tX, tXX, tY, tXY;
+  int i;
+
+  int lo, hi;
+  float R, A, B, D;
+  float w, x, y;
+
+  tN = tX = tXX = tY = tXY = 0.f;
+
+  y = f[0] + offset;
+  if (y < 1.f) y = 1.f;
+
+  w = y * y * .5;
+    
+  tN += w;
+  tX += w;
+  tY += w * y;
+
+  N[0] = tN;
+  X[0] = tX;
+  XX[0] = tXX;
+  Y[0] = tY;
+  XY[0] = tXY;
+
+  for (i = 1, x = 1.f; i < n; i++, x += 1.f) {
+    
+    y = f[i] + offset;
+    if (y < 1.f) y = 1.f;
+
+    w = y * y;
+    
+    tN += w;
+    tX += w * x;
+    tXX += w * x * x;
+    tY += w * y;
+    tXY += w * x * y;
+
+    N[i] = tN;
+    X[i] = tX;
+    XX[i] = tXX;
+    Y[i] = tY;
+    XY[i] = tXY;
+  }
+  
+  for (i = 0, x = 0.f;; i++, x += 1.f) {
+    
+    lo = b[i] >> 16;
+    if( lo>=0 ) break;
+    hi = b[i] & 0xffff;
+    
+    tN = N[hi] + N[-lo];
+    tX = X[hi] - X[-lo];
+    tXX = XX[hi] + XX[-lo];
+    tY = Y[hi] + Y[-lo];    
+    tXY = XY[hi] - XY[-lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    if (R < 0.f)
+      R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  
+  for ( ;; i++, x += 1.f) {
+    
+    lo = b[i] >> 16;
+    hi = b[i] & 0xffff;
+    if(hi>=n)break;
+    
+    tN = N[hi] - N[lo];
+    tX = X[hi] - X[lo];
+    tXX = XX[hi] - XX[lo];
+    tY = Y[hi] - Y[lo];
+    tXY = XY[hi] - XY[lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    if (R < 0.f) R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  for ( ; i < n; i++, x += 1.f) {
+    
+    R = (A + x * B) / D;
+    if (R < 0.f) R = 0.f;
+    
+    noise[i] = R - offset;
+  }
+  
+  if (fixed <= 0) return;
+  
+  for (i = 0, x = 0.f;; i++, x += 1.f) {
+    hi = i + fixed / 2;
+    lo = hi - fixed;
+    if(lo>=0)break;
+
+    tN = N[hi] + N[-lo];
+    tX = X[hi] - X[-lo];
+    tXX = XX[hi] + XX[-lo];
+    tY = Y[hi] + Y[-lo];
+    tXY = XY[hi] - XY[-lo];
+    
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+  for ( ;; i++, x += 1.f) {
+    
+    hi = i + fixed / 2;
+    lo = hi - fixed;
+    if(hi>=n)break;
+    
+    tN = N[hi] - N[lo];
+    tX = X[hi] - X[lo];
+    tXX = XX[hi] - XX[lo];
+    tY = Y[hi] - Y[lo];
+    tXY = XY[hi] - XY[lo];
+    
+    A = tY * tXX - tX * tXY;
+    B = tN * tXY - tX * tY;
+    D = tN * tXX - tX * tX;
+    R = (A + x * B) / D;
+    
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+  for ( ; i < n; i++, x += 1.f) {
+    R = (A + x * B) / D;
+    if (R - offset < noise[i]) noise[i] = R - offset;
+  }
+}
+
+static void _vp_noisemask(VorbisPsy *p,
+			  float *logfreq, 
+			  float *logmask){
+
+  int i,n=p->n/2;
+  float *work=alloca(n*sizeof(*work));
+
+  bark_noise_hybridmp(n,p->bark,logfreq,logmask,
+		      140.,-1);
+
+  for(i=0;i<n;i++)work[i]=logfreq[i]-logmask[i];
+
+  bark_noise_hybridmp(n,p->bark,work,logmask,0.,
+		      p->vi->noisewindowfixed);
+
+  for(i=0;i<n;i++)work[i]=logfreq[i]-work[i];
+  
+  {
+    static int seq=0;
+    
+    float work2[n];
+    for(i=0;i<n;i++){
+      work2[i]=logmask[i]+work[i];
+    }
+    
+    //_analysis_output("logfreq",seq,logfreq,n,0,0);
+    //_analysis_output("median",seq,work,n,0,0);
+    //_analysis_output("envelope",seq,work2,n,0,0);
+    seq++;
+  }
+
+  for(i=0;i<n;i++){
+    int dB=logmask[i]+.5;
+    if(dB>=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1;
+    if(dB<0)dB=0;
+    logmask[i]= work[i]+p->vi->noisecompand[dB]+p->noiseoffset[i];
+  }
+
+}
+
+VorbisPsy *vorbis_psy_init(int rate, int n)
+{
+  long i,j,lo=-99,hi=1;
+  VorbisPsy *p = speex_alloc(sizeof(VorbisPsy));
+  memset(p,0,sizeof(*p));
+  
+  p->n = n;
+  spx_drft_init(&p->lookup, n);
+  p->bark = speex_alloc(n*sizeof(*p->bark));
+  p->rate=rate;
+  p->vi = &example_tuning;
+
+  /* BH4 window */
+  p->window = speex_alloc(sizeof(*p->window)*n);
+  float a0 = .35875f;
+  float a1 = .48829f;
+  float a2 = .14128f;
+  float a3 = .01168f;
+  for(i=0;i<n;i++)
+    p->window[i] = //a0 - a1*cos(2.*M_PI/n*(i+.5)) + a2*cos(4.*M_PI/n*(i+.5)) - a3*cos(6.*M_PI/n*(i+.5));
+      sin((i+.5)/n * M_PI)*sin((i+.5)/n * M_PI);
+  /* bark scale lookups */
+  for(i=0;i<n;i++){
+    float bark=toBARK(rate/(2*n)*i); 
+    
+    for(;lo+p->vi->noisewindowlomin<i && 
+	  toBARK(rate/(2*n)*lo)<(bark-p->vi->noisewindowlo);lo++);
+    
+    for(;hi<=n && (hi<i+p->vi->noisewindowhimin ||
+	  toBARK(rate/(2*n)*hi)<(bark+p->vi->noisewindowhi));hi++);
+    
+    p->bark[i]=((lo-1)<<16)+(hi-1);
+
+  }
+
+  /* set up rolling noise median */
+  p->noiseoffset=speex_alloc(n*sizeof(*p->noiseoffset));
+  
+  for(i=0;i<n;i++){
+    float halfoc=toOC((i+.5)*rate/(2.*n))*2.;
+    int inthalfoc;
+    float del;
+    
+    if(halfoc<0)halfoc=0;
+    if(halfoc>=P_BANDS-1)halfoc=P_BANDS-1;
+    inthalfoc=(int)halfoc;
+    del=halfoc-inthalfoc;
+    
+    p->noiseoffset[i]=
+      p->vi->noiseoff[inthalfoc]*(1.-del) + 
+      p->vi->noiseoff[inthalfoc+1]*del;
+    
+  }
+#if 0
+  _analysis_output_always("noiseoff0",ls,p->noiseoffset,n,1,0,0);
+#endif
+
+   return p;
+}
+
+void vorbis_psy_destroy(VorbisPsy *p)
+{
+  if(p){
+    spx_drft_clear(&p->lookup);
+    if(p->bark)
+      speex_free(p->bark);
+    if(p->noiseoffset)
+      speex_free(p->noiseoffset);
+    if(p->window)
+      speex_free(p->window);
+    memset(p,0,sizeof(*p));
+    speex_free(p);
+  }
+}
+
+void compute_curve(VorbisPsy *psy, float *audio, float *curve)
+{
+   int i;
+   float work[psy->n];
+
+   float scale=4.f/psy->n;
+   float scale_dB;
+
+   scale_dB=todB(scale);
+  
+   /* window the PCM data; use a BH4 window, not vorbis */
+   for(i=0;i<psy->n;i++)
+     work[i]=audio[i] * psy->window[i];
+
+   {
+     static int seq=0;
+     
+     //_analysis_output("win",seq,work,psy->n,0,0);
+
+     seq++;
+   }
+
+    /* FFT yields more accurate tonal estimation (not phase sensitive) */
+    spx_drft_forward(&psy->lookup,work);
+
+    /* magnitudes */
+    work[0]=scale_dB+todB(work[0]);
+    for(i=1;i<psy->n-1;i+=2){
+      float temp = work[i]*work[i] + work[i+1]*work[i+1];
+      work[(i+1)>>1] = scale_dB+.5f * todB(temp);
+    }
+
+    /* derive a noise curve */
+    _vp_noisemask(psy,work,curve);
+#define SIDEL 12
+    for (i=0;i<SIDEL;i++)
+    {
+       curve[i]=curve[SIDEL];
+    }
+#define SIDEH 12
+    for (i=0;i<SIDEH;i++)
+    {
+       curve[(psy->n>>1)-i-1]=curve[(psy->n>>1)-SIDEH];
+    }
+    for(i=0;i<((psy->n)>>1);i++)
+       curve[i] = fromdB(1.2*curve[i]+.2*i);
+       //curve[i] = fromdB(0.8*curve[i]+.35*i);
+       //curve[i] = fromdB(0.9*curve[i])*pow(1.0*i+45,1.3);
+}
+
+/* Transform a masking curve (power spectrum) into a pole-zero filter */
+void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord)
+{
+   int i;
+   float ac[psy->n];
+   float tmp;
+   int len = psy->n >> 1;
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;
+   for (i=1;i<len;i++)
+      ac[2*i-1] = curve[i];
+   ac[0] = curve[0];
+   ac[2*len-1] = curve[len-1];
+   
+   spx_drft_backward(&psy->lookup, ac);
+   _spx_lpc(awk1, ac, ord);
+   tmp = 1.;
+   for (i=0;i<ord;i++)
+   {
+      tmp *= .99;
+      awk1[i] *= tmp;
+   }
+#if 0
+   for (i=0;i<ord;i++)
+      awk2[i] = 0;
+#else
+   /* Use the second (awk2) filter to correct the first one */
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;   
+   for (i=0;i<ord;i++)
+      ac[i+1] = awk1[i];
+   ac[0] = 1;
+   spx_drft_forward(&psy->lookup, ac);
+   /* Compute (power) response of awk1 (all zero) */
+   ac[0] *= ac[0];
+   for (i=1;i<len;i++)
+      ac[i] = ac[2*i-1]*ac[2*i-1] + ac[2*i]*ac[2*i];
+   ac[len] = ac[2*len-1]*ac[2*len-1];
+   /* Compute correction required */
+   for (i=0;i<len;i++)
+      curve[i] = 1. / (1e-6f+curve[i]*ac[i]);
+
+   for (i=0;i<2*len;i++)
+      ac[i] = 0;
+   for (i=1;i<len;i++)
+      ac[2*i-1] = curve[i];
+   ac[0] = curve[0];
+   ac[2*len-1] = curve[len-1];
+   
+   spx_drft_backward(&psy->lookup, ac);
+   _spx_lpc(awk2, ac, ord);
+   tmp = 1;
+   for (i=0;i<ord;i++)
+   {
+      tmp *= .99;
+      awk2[i] *= tmp;
+   }
+#endif
+}
+
+#if 0
+#include <stdio.h>
+#include <math.h>
+
+#define ORDER 10
+#define CURVE_SIZE 24
+
+int main()
+{
+   int i;
+   float curve[CURVE_SIZE];
+   float awk1[ORDER], awk2[ORDER];
+   for (i=0;i<CURVE_SIZE;i++)
+      scanf("%f ", &curve[i]);
+   for (i=0;i<CURVE_SIZE;i++)
+      curve[i] = pow(10.f, .1*curve[i]);
+   curve_to_lpc(curve, CURVE_SIZE, awk1, awk2, ORDER);
+   for (i=0;i<ORDER;i++)
+      printf("%f ", awk1[i]);
+   printf ("\n");
+   for (i=0;i<ORDER;i++)
+      printf("%f ", awk2[i]);
+   printf ("\n");
+   return 0;
+}
+#endif
+
+#endif
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef16fc2203f83ab2d7a78ce72a65081c437e56d8.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef16fc2203f83ab2d7a78ce72a65081c437e56d8.svn-base
new file mode 100644
index 0000000..0170f6f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef16fc2203f83ab2d7a78ce72a65081c437e56d8.svn-base
@@ -0,0 +1,24 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009-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 
+ */
+
+/*
+ * This file is a C++ wrapper, see ticket #886 for details.
+ */
+
+#include "sip_endpoint.c"
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef174868bb97ac011acaab0582193cd873654658.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef174868bb97ac011acaab0582193cd873654658.svn-base
new file mode 100644
index 0000000..97fadb5
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef174868bb97ac011acaab0582193cd873654658.svn-base
Binary files differ
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef2727526ae3a7c64bb9e58826d3fe65445e6485.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef2727526ae3a7c64bb9e58826d3fe65445e6485.svn-base
new file mode 100644
index 0000000..94d03af
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef2727526ae3a7c64bb9e58826d3fe65445e6485.svn-base
@@ -0,0 +1,13 @@
+export HOST_MV := mv
+export HOST_RM := rm -f @@
+export HOST_RMR := rm -rf @@
+export HOST_RMDIR := rm -rf @@
+export HOST_MKDIR := mkdir @@
+export HOST_EXE := .exe
+export HOST_PSEP := /
+
+export HOST_SOURCES :=
+export HOST_CFLAGS :=
+export HOST_CXXFLAGS :=
+export HOST_LDFLAGS := $(CC_LIB)stdc++$(LIBEXT2)
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/ef57a0900f91bcc0130fc6d2ce35de5f21bc51e5.svn-base b/jni/pjproject-android/.svn/pristine/ef/ef57a0900f91bcc0130fc6d2ce35de5f21bc51e5.svn-base
new file mode 100644
index 0000000..74f3d93
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/ef57a0900f91bcc0130fc6d2ce35de5f21bc51e5.svn-base
@@ -0,0 +1,728 @@
+/****************************************************************************
+**
+**   ITU-T G.722.1 (2005-05) - Fixed point implementation for main body and Annex C
+**   > Software Release 2.1 (2008-06)
+**     (Simple repackaging; no change from 2005-05 Release 2.0 code)
+**
+**   © 2004 Polycom, Inc.
+**
+**	 All rights reserved.
+**
+****************************************************************************/
+
+/****************************************************************************
+  Filename:    dct4_a.h    
+
+  Purpose:     Contains tables used by dct4_a.c
+		
+  Design Notes:
+
+****************************************************************************/
+
+/***************************************************************************
+ Include files                                                           
+***************************************************************************/
+#include <stdio.h>
+#include <math.h>
+
+typedef struct 
+{
+    Word16	cosine;
+    Word16	minus_sine;
+} cos_msin_t;
+
+cos_msin_t	a_cos_msin_2[10] = {
+    {  29805   ,   -1171   } , 
+    {  29621   ,   -3506   } , 
+    {  29255   ,   -5819   } , 
+    {  28708   ,   -8097   } , 
+    {  27984   ,   -10324   } , 
+    {  27088   ,   -12488   } , 
+    {  26025   ,   -14575   } , 
+    {  24801   ,   -16572   } , 
+    {  23425   ,   -18466   } , 
+    {  21903   ,   -20247   }  
+    }; 
+cos_msin_t	a_cos_msin_4[20] = {
+    {  29822   ,   -586   } , 
+    {  29776   ,   -1756   } , 
+    {  29684   ,   -2924   } , 
+    {  29547   ,   -4087   } , 
+    {  29364   ,   -5244   } , 
+    {  29135   ,   -6392   } , 
+    {  28862   ,   -7531   } , 
+    {  28544   ,   -8659   } , 
+    {  28182   ,   -9773   } , 
+    {  27776   ,   -10871   } , 
+    {  27328   ,   -11954   } , 
+    {  26838   ,   -13017   } , 
+    {  26306   ,   -14061   } , 
+    {  25734   ,   -15083   } , 
+    {  25122   ,   -16081   } , 
+    {  24471   ,   -17055   } , 
+    {  23783   ,   -18003   } , 
+    {  23057   ,   -18923   } , 
+    {  22297   ,   -19813   } , 
+    {  21502   ,   -20673   } 
+    };
+cos_msin_t	a_cos_msin_8[40] = {
+    {  29827   ,   -293   } , 
+    {  29815   ,   -878   } , 
+    {  29792   ,   -1464   } , 
+    {  29758   ,   -2048   } , 
+    {  29712   ,   -2632   } , 
+    {  29654   ,   -3215   } , 
+    {  29586   ,   -3797   } , 
+    {  29505   ,   -4377   } , 
+    {  29414   ,   -4955   } , 
+    {  29311   ,   -5532   } , 
+    {  29196   ,   -6106   } , 
+    {  29071   ,   -6678   } , 
+    {  28934   ,   -7248   } , 
+    {  28786   ,   -7814   } , 
+    {  28627   ,   -8378   } , 
+    {  28457   ,   -8938   } , 
+    {  28276   ,   -9495   } , 
+    {  28084   ,   -10049   } , 
+    {  27882   ,   -10598   } , 
+    {  27668   ,   -11144   } , 
+    {  27444   ,   -11685   } , 
+    {  27209   ,   -12221   } , 
+    {  26964   ,   -12753   } , 
+    {  26709   ,   -13280   } , 
+    {  26443   ,   -13802   } , 
+    {  26167   ,   -14318   } , 
+    {  25881   ,   -14829   } , 
+    {  25584   ,   -15335   } , 
+    {  25278   ,   -15834   } , 
+    {  24963   ,   -16327   } , 
+    {  24637   ,   -16814   } , 
+    {  24302   ,   -17295   } , 
+    {  23958   ,   -17769   } , 
+    {  23605   ,   -18236   } , 
+    {  23242   ,   -18695   } , 
+    {  22871   ,   -19148   } , 
+    {  22490   ,   -19594   } , 
+    {  22101   ,   -20031   } , 
+    {  21704   ,   -20461   } , 
+    {  21298   ,   -20884   } 
+    };
+cos_msin_t	a_cos_msin_16[80] = {
+    {  29828   ,   -146   } , 
+    {  29825   ,   -439   } , 
+    {  29819   ,   -732   } , 
+    {  29811   ,   -1025   } , 
+    {  29799   ,   -1317   } , 
+    {  29785   ,   -1610   } , 
+    {  29767   ,   -1902   } , 
+    {  29747   ,   -2194   } , 
+    {  29724   ,   -2486   } , 
+    {  29698   ,   -2778   } , 
+    {  29670   ,   -3069   } , 
+    {  29638   ,   -3360   } , 
+    {  29604   ,   -3651   } , 
+    {  29567   ,   -3942   } , 
+    {  29526   ,   -4232   } , 
+    {  29483   ,   -4521   } , 
+    {  29438   ,   -4811   } , 
+    {  29389   ,   -5099   } , 
+    {  29338   ,   -5388   } , 
+    {  29283   ,   -5676   } , 
+    {  29226   ,   -5963   } , 
+    {  29166   ,   -6249   } , 
+    {  29103   ,   -6535   } , 
+    {  29038   ,   -6821   } , 
+    {  28969   ,   -7106   } , 
+    {  28898   ,   -7390   } , 
+    {  28824   ,   -7673   } , 
+    {  28748   ,   -7956   } , 
+    {  28668   ,   -8237   } , 
+    {  28586   ,   -8518   } , 
+    {  28501   ,   -8799   } , 
+    {  28413   ,   -9078   } , 
+    {  28323   ,   -9357   } , 
+    {  28229   ,   -9634   } , 
+    {  28133   ,   -9911   } , 
+    {  28035   ,   -10187   } , 
+    {  27933   ,   -10461   } , 
+    {  27829   ,   -10735   } , 
+    {  27723   ,   -11008   } , 
+    {  27613   ,   -11279   } , 
+    {  27501   ,   -11550   } , 
+    {  27387   ,   -11819   } , 
+    {  27269   ,   -12088   } , 
+    {  27149   ,   -12355   } , 
+    {  27027   ,   -12621   } , 
+    {  26901   ,   -12885   } , 
+    {  26774   ,   -13149   } , 
+    {  26643   ,   -13411   } , 
+    {  26510   ,   -13672   } , 
+    {  26375   ,   -13932   } , 
+    {  26237   ,   -14190   } , 
+    {  26096   ,   -14447   } , 
+    {  25953   ,   -14702   } , 
+    {  25807   ,   -14956   } , 
+    {  25659   ,   -15209   } , 
+    {  25509   ,   -15460   } , 
+    {  25356   ,   -15710   } , 
+    {  25200   ,   -15958   } , 
+    {  25043   ,   -16205   } , 
+    {  24882   ,   -16450   } , 
+    {  24720   ,   -16693   } , 
+    {  24554   ,   -16935   } , 
+    {  24387   ,   -17175   } , 
+    {  24217   ,   -17414   } , 
+    {  24045   ,   -17651   } , 
+    {  23871   ,   -17886   } , 
+    {  23694   ,   -18119   } , 
+    {  23515   ,   -18351   } , 
+    {  23334   ,   -18581   } , 
+    {  23150   ,   -18809   } , 
+    {  22964   ,   -19036   } , 
+    {  22776   ,   -19260   } , 
+    {  22586   ,   -19483   } , 
+    {  22394   ,   -19704   } , 
+    {  22199   ,   -19923   } , 
+    {  22003   ,   -20140   } , 
+    {  21804   ,   -20355   } , 
+    {  21603   ,   -20568   } , 
+    {  21400   ,   -20779   } , 
+    {  21195   ,   -20988   } 
+    };
+cos_msin_t	a_cos_msin_32[160]= {
+    {  29828   ,   -73   } , 
+    {  29827   ,   -220   } , 
+    {  29826   ,   -366   } , 
+    {  29824   ,   -512   } , 
+    {  29821   ,   -659   } , 
+    {  29817   ,   -805   } , 
+    {  29813   ,   -952   } , 
+    {  29808   ,   -1098   } , 
+    {  29802   ,   -1244   } , 
+    {  29796   ,   -1390   } , 
+    {  29789   ,   -1537   } , 
+    {  29781   ,   -1683   } , 
+    {  29772   ,   -1829   } , 
+    {  29763   ,   -1975   } , 
+    {  29753   ,   -2121   } , 
+    {  29742   ,   -2267   } , 
+    {  29730   ,   -2413   } , 
+    {  29718   ,   -2559   } , 
+    {  29705   ,   -2705   } , 
+    {  29692   ,   -2851   } , 
+    {  29677   ,   -2997   } , 
+    {  29662   ,   -3142   } , 
+    {  29646   ,   -3288   } , 
+    {  29630   ,   -3433   } , 
+    {  29613   ,   -3579   } , 
+    {  29595   ,   -3724   } , 
+    {  29576   ,   -3869   } , 
+    {  29557   ,   -4014   } , 
+    {  29537   ,   -4159   } , 
+    {  29516   ,   -4304   } , 
+    {  29494   ,   -4449   } , 
+    {  29472   ,   -4594   } , 
+    {  29449   ,   -4738   } , 
+    {  29426   ,   -4883   } , 
+    {  29401   ,   -5027   } , 
+    {  29376   ,   -5172   } , 
+    {  29351   ,   -5316   } , 
+    {  29324   ,   -5460   } , 
+    {  29297   ,   -5604   } , 
+    {  29269   ,   -5747   } , 
+    {  29241   ,   -5891   } , 
+    {  29211   ,   -6034   } , 
+    {  29181   ,   -6178   } , 
+    {  29151   ,   -6321   } , 
+    {  29119   ,   -6464   } , 
+    {  29087   ,   -6607   } , 
+    {  29054   ,   -6749   } , 
+    {  29021   ,   -6892   } , 
+    {  28987   ,   -7034   } , 
+    {  28952   ,   -7177   } , 
+    {  28916   ,   -7319   } , 
+    {  28880   ,   -7460   } , 
+    {  28843   ,   -7602   } , 
+    {  28805   ,   -7744   } , 
+    {  28767   ,   -7885   } , 
+    {  28728   ,   -8026   } , 
+    {  28688   ,   -8167   } , 
+    {  28648   ,   -8308   } , 
+    {  28607   ,   -8448   } , 
+    {  28565   ,   -8589   } , 
+    {  28522   ,   -8729   } , 
+    {  28479   ,   -8869   } , 
+    {  28435   ,   -9008   } , 
+    {  28391   ,   -9148   } , 
+    {  28346   ,   -9287   } , 
+    {  28300   ,   -9426   } , 
+    {  28253   ,   -9565   } , 
+    {  28206   ,   -9703   } , 
+    {  28158   ,   -9842   } , 
+    {  28109   ,   -9980   } , 
+    {  28060   ,   -10118   } , 
+    {  28010   ,   -10255   } , 
+    {  27959   ,   -10393   } , 
+    {  27908   ,   -10530   } , 
+    {  27856   ,   -10667   } , 
+    {  27803   ,   -10803   } , 
+    {  27750   ,   -10940   } , 
+    {  27696   ,   -11076   } , 
+    {  27641   ,   -11212   } , 
+    {  27586   ,   -11347   } , 
+    {  27529   ,   -11482   } , 
+    {  27473   ,   -11617   } , 
+    {  27415   ,   -11752   } , 
+    {  27357   ,   -11886   } , 
+    {  27299   ,   -12021   } , 
+    {  27239   ,   -12154   } , 
+    {  27179   ,   -12288   } , 
+    {  27119   ,   -12421   } , 
+    {  27057   ,   -12554   } , 
+    {  26996   ,   -12687   } , 
+    {  26933   ,   -12819   } , 
+    {  26870   ,   -12951   } , 
+    {  26806   ,   -13083   } , 
+    {  26741   ,   -13215   } , 
+    {  26676   ,   -13346   } , 
+    {  26610   ,   -13476   } , 
+    {  26544   ,   -13607   } , 
+    {  26477   ,   -13737   } , 
+    {  26409   ,   -13867   } , 
+    {  26340   ,   -13996   } , 
+    {  26271   ,   -14125   } , 
+    {  26202   ,   -14254   } , 
+    {  26132   ,   -14383   } , 
+    {  26061   ,   -14511   } , 
+    {  25989   ,   -14638   } , 
+    {  25917   ,   -14766   } , 
+    {  25844   ,   -14893   } , 
+    {  25771   ,   -15020   } , 
+    {  25697   ,   -15146   } , 
+    {  25622   ,   -15272   } , 
+    {  25547   ,   -15397   } , 
+    {  25471   ,   -15523   } , 
+    {  25394   ,   -15648   } , 
+    {  25317   ,   -15772   } , 
+    {  25239   ,   -15896   } , 
+    {  25161   ,   -16020   } , 
+    {  25082   ,   -16143   } , 
+    {  25003   ,   -16266   } , 
+    {  24923   ,   -16389   } , 
+    {  24842   ,   -16511   } , 
+    {  24760   ,   -16632   } , 
+    {  24678   ,   -16754   } , 
+    {  24596   ,   -16875   } , 
+    {  24513   ,   -16995   } , 
+    {  24429   ,   -17115   } , 
+    {  24345   ,   -17235   } , 
+    {  24260   ,   -17354   } , 
+    {  24174   ,   -17473   } , 
+    {  24088   ,   -17592   } , 
+    {  24002   ,   -17710   } , 
+    {  23914   ,   -17827   } , 
+    {  23827   ,   -17945   } , 
+    {  23738   ,   -18061   } , 
+    {  23649   ,   -18178   } , 
+    {  23560   ,   -18293   } , 
+    {  23470   ,   -18409   } , 
+    {  23379   ,   -18524   } , 
+    {  23288   ,   -18638   } , 
+    {  23196   ,   -18752   } , 
+    {  23104   ,   -18866   } , 
+    {  23011   ,   -18979   } , 
+    {  22917   ,   -19092   } , 
+    {  22824   ,   -19204   } , 
+    {  22729   ,   -19316   } , 
+    {  22634   ,   -19427   } , 
+    {  22538   ,   -19538   } , 
+    {  22442   ,   -19649   } , 
+    {  22345   ,   -19759   } , 
+    {  22248   ,   -19868   } , 
+    {  22150   ,   -19977   } , 
+    {  22052   ,   -20086   } , 
+    {  21953   ,   -20194   } , 
+    {  21854   ,   -20301   } , 
+    {  21754   ,   -20408   } , 
+    {  21653   ,   -20515   } , 
+    {  21552   ,   -20621   } , 
+    {  21451   ,   -20726   } , 
+    {  21349   ,   -20831   } , 
+    {  21246   ,   -20936   } , 
+    {  21143   ,   -21040   } 
+    };
+cos_msin_t	a_cos_msin_64[320] = {
+{29827,	-34},
+{29827,	-106},
+{29827,	-177},
+{29827,	-249},
+{29826,	-320},
+{29825,	-392},
+{29824,	-463},
+{29823,	-535},
+{29821,	-606},
+{29819,	-678},
+{29818,	-750},
+{29816,	-821},
+{29814,	-893},
+{29812,	-964},
+{29809,	-1035},
+{29807,	-1106},
+{29804,	-1177},
+{29801,	-1249},
+{29797,	-1320},
+{29795,	-1392},
+{29791,	-1463},
+{29787,	-1535},
+{29784,	-1606},
+{29780,	-1678},
+{29776,	-1749},
+{29771,	-1820},
+{29767,	-1892},
+{29763,	-1963},
+{29758,	-2035},
+{29753,	-2106},
+{29748,	-2177},
+{29742,	-2249},
+{29737,	-2320},
+{29731,	-2391},
+{29726,	-2462},
+{29719,	-2534},
+{29713,	-2605},
+{29707,	-2676},
+{29701,	-2747},
+{29694,	-2819},
+{29686,	-2890},
+{29680,	-2961},
+{29673,	-3032},
+{29665,	-3103},
+{29658,	-3174},
+{29650,	-3245},
+{29643,	-3316},
+{29635,	-3387},
+{29626,	-3459},
+{29618,	-3529},
+{29610,	-3600},
+{29601,	-3671},
+{29592,	-3742},
+{29583,	-3813},
+{29574,	-3884},
+{29564,	-3955},
+{29554,	-4026},
+{29544,	-4097},
+{29535,	-4167},
+{29525,	-4238},
+{29514,	-4309},
+{29504,	-4380},
+{29493,	-4450},
+{29483,	-4521},
+{29472,	-4591},
+{29461,	-4662},
+{29450,	-4733},
+{29439,	-4803},
+{29427,	-4874},
+{29415,	-4944},
+{29403,	-5015},
+{29391,	-5085},
+{29379,	-5155},
+{29366,	-5226},
+{29353,	-5296},
+{29341,	-5367},
+{29328,	-5438},
+{29314,	-5508},
+{29301,	-5578},
+{29289,	-5648},
+{29274,	-5718},
+{29260,	-5788},
+{29247,	-5858},
+{29232,	-5928},
+{29218,	-5998},
+{29204,	-6068},
+{29188,	-6139},
+{29175,	-6209},
+{29159,	-6279},
+{29145,	-6348},
+{29128,	-6418},
+{29114,	-6488},
+{29097,	-6557},
+{29082,	-6627},
+{29066,	-6697},
+{29050,	-6767},
+{29034,	-6837},
+{29017,	-6906},
+{29001,	-6975},
+{28984,	-7045},
+{28966,	-7114},
+{28950,	-7184},
+{28933,	-7254},
+{28915,	-7323},
+{28897,	-7392},
+{28880,	-7461},
+{28862,	-7530},
+{28843,	-7600},
+{28825,	-7669},
+{28807,	-7738},
+{28788,	-7806},
+{28769,	-7875},
+{28751,	-7944},
+{28732,	-8014},
+{28712,	-8082},
+{28692,	-8151},
+{28672,	-8219},
+{28653,	-8289},
+{28633,	-8357},
+{28613,	-8425},
+{28593,	-8494},
+{28572,	-8563},
+{28551,	-8632},
+{28531,	-8700},
+{28510,	-8768},
+{28488,	-8837},
+{28468,	-8905},
+{28447,	-8973},
+{28425,	-9041},
+{28403,	-9109},
+{28381,	-9177},
+{28359,	-9245},
+{28336,	-9313},
+{28315,	-9381},
+{28292,	-9448},
+{28269,	-9517},
+{28246,	-9584},
+{28223,	-9652},
+{28200,	-9720},
+{28176,	-9787},
+{28153,	-9854},
+{28129,	-9922},
+{28105,	-9990},
+{28082,	-10056},
+{28057,	-10124},
+{28032,	-10191},
+{28009,	-10258},
+{27984,	-10326},
+{27959,	-10392},
+{27934,	-10460},
+{27909,	-10526},
+{27883,	-10593},
+{27858,	-10661},
+{27832,	-10727},
+{27807,	-10794},
+{27780,	-10860},
+{27754,	-10927},
+{27728,	-10993},
+{27701,	-11059},
+{27676,	-11126},
+{27648,	-11192},
+{27622,	-11259},
+{27595,	-11324},
+{27567,	-11391},
+{27540,	-11456},
+{27512,	-11523},
+{27484,	-11588},
+{27456,	-11655},
+{27429,	-11720},
+{27401,	-11786},
+{27372,	-11852},
+{27344,	-11917},
+{27315,	-11982},
+{27286,	-12049},
+{27257,	-12114},
+{27229,	-12179},
+{27199,	-12244},
+{27169,	-12309},
+{27140,	-12375},
+{27110,	-12439},
+{27080,	-12505},
+{27050,	-12570},
+{27019,	-12634},
+{26990,	-12699},
+{26958,	-12764},
+{26928,	-12828},
+{26897,	-12892},
+{26866,	-12956},
+{26835,	-13021},
+{26804,	-13086},
+{26773,	-13149},
+{26741,	-13214},
+{26709,	-13278},
+{26677,	-13342},
+{26645,	-13406},
+{26613,	-13470},
+{26581,	-13534},
+{26549,	-13597},
+{26515,	-13661},
+{26483,	-13725},
+{26450,	-13788},
+{26417,	-13851},
+{26384,	-13915},
+{26350,	-13978},
+{26316,	-14041},
+{26283,	-14103},
+{26248,	-14166},
+{26215,	-14229},
+{26180,	-14292},
+{26146,	-14355},
+{26112,	-14417},
+{26077,	-14480},
+{26042,	-14543},
+{26008,	-14605},
+{25972,	-14667},
+{25937,	-14730},
+{25901,	-14792},
+{25866,	-14854},
+{25830,	-14916},
+{25794,	-14977},
+{25759,	-15039},
+{25723,	-15101},
+{25687,	-15162},
+{25650,	-15224},
+{25613,	-15286},
+{25577,	-15347},
+{25540,	-15408},
+{25503,	-15470},
+{25465,	-15531},
+{25428,	-15592},
+{25391,	-15653},
+{25353,	-15714},
+{25315,	-15774},
+{25277,	-15834},
+{25240,	-15895},
+{25201,	-15956},
+{25162,	-16016},
+{25124,	-16076},
+{25086,	-16136},
+{25047,	-16196},
+{25008,	-16256},
+{24969,	-16316},
+{24930,	-16375},
+{24891,	-16436},
+{24851,	-16496},
+{24811,	-16555},
+{24772,	-16615},
+{24732,	-16674},
+{24692,	-16732},
+{24652,	-16791},
+{24612,	-16852},
+{24572,	-16911},
+{24531,	-16969},
+{24490,	-17027},
+{24449,	-17086},
+{24408,	-17145},
+{24367,	-17203},
+{24325,	-17261},
+{24284,	-17320},
+{24242,	-17379},
+{24200,	-17436},
+{24158,	-17494},
+{24116,	-17552},
+{24075,	-17610},
+{24032,	-17668},
+{23990,	-17725},
+{23947,	-17782},
+{23904,	-17840},
+{23862,	-17897},
+{23819,	-17954},
+{23775,	-18011},
+{23732,	-18068},
+{23689,	-18125},
+{23645,	-18181},
+{23602,	-18238},
+{23558,	-18294},
+{23514,	-18351},
+{23470,	-18407},
+{23426,	-18464},
+{23381,	-18520},
+{23337,	-18576},
+{23293,	-18632},
+{23248,	-18688},
+{23202,	-18743},
+{23158,	-18799},
+{23112,	-18854},
+{23068,	-18910},
+{23022,	-18964},
+{22977,	-19020},
+{22931,	-19074},
+{22885,	-19129},
+{22839,	-19185},
+{22793,	-19239},
+{22747,	-19294},
+{22700,	-19348},
+{22655,	-19403},
+{22607,	-19457},
+{22561,	-19511},
+{22514,	-19565},
+{22467,	-19619},
+{22421,	-19673},
+{22373,	-19726},
+{22326,	-19780},
+{22279,	-19834},
+{22230,	-19887},
+{22183,	-19940},
+{22135,	-19993},
+{22087,	-20047},
+{22039,	-20099},
+{21991,	-20152},
+{21942,	-20205},
+{21894,	-20257},
+{21845,	-20309},
+{21797,	-20362},
+{21748,	-20413},
+{21699,	-20466},
+{21650,	-20518},
+{21601,	-20570},
+{21551,	-20621},
+{21502,	-20674}
+};
+
+cos_msin_t	*a_cos_msin_table[] = {a_cos_msin_2, a_cos_msin_4,
+                                   a_cos_msin_8, a_cos_msin_16,
+                                   a_cos_msin_32,a_cos_msin_64
+			                      };
+
+Word16 dct_core_a[10][10] = {
+
+{ 10453,  10196,   9688,   8941,   7973,   6810,   5479,   4013,   2448,    823 },
+{ 10196,   7973,   4013,   -823,  -5479,  -8941, -10453,  -9688,  -6810,  -2448 },
+{ 9688 ,   4013,  -4013,  -9688,  -9688,  -4013,   4013,   9688,   9688,   4013 },
+{ 8941 ,   -823,  -9688,  -7973,   2448,  10196,   6810,  -4013, -10453,  -5479 },
+{ 7973 ,  -5479,  -9688,   2448,  10453,    823, -10196,  -4013,   8941,   6810 },
+{ 6810 ,  -8941,  -4013,  10196,    823, -10453,   2448,   9688,  -5479,  -7973 },
+{ 5479 , -10453,   4013,   6810, -10196,   2448,   7973,  -9688,    823,   8941 },
+{ 4013 ,  -9688,   9688,  -4013,  -4013,   9688,  -9688,   4013,   4013,  -9688 },
+{ 2448 ,  -6810,   9688, -10453,   8941,  -5479,    823,   4013,  -7973,  10196 },
+{ 823  ,  -2448,   4013,  -5479,   6810,  -7973,   8941,  -9688,  10196, -10453 }};
+
+Word16 anal_bias[320] = {
+  1,  1,  3,  1,  4,  1,  3, -2,  4,  3,
+  4,  1,  3,  0,  2, -3,  0,  0,  2,  2,
+  4,  1,  1, -5,  4,  1,  2, -1,  0, -1,
+  1, -2,  0,  2,  2,  2,  4,  1,  3,  0,
+  5,  3,  2,  0,  3,  0,  1, -4,  1,  1,
+  2,  0,  4,  0,  1, -4,  6,  1,  3, -1,
+  1,  0,  0, -4,  1,  1,  3,  1,  3,  2,
+  4, -2,  4,  3,  5,  1,  3,  0,  1, -3,
+  1,  1,  2,  0,  4,  1,  2, -4,  4,  2,
+  2, -1,  1, -1,  1, -4,  0,  0,  3,  0,
+  5,  2,  3, -1,  6,  2,  5,  0,  4,  0,
+  1, -3,  1,  0,  3,  0,  4,  0,  1, -3,
+  4,  1,  3, -1,  1, -2,  1, -4,  0,  1,
+  2,  1,  3,  2,  2, -2,  4,  3,  3,  0,
+  3,  0,  0, -2,  1,  0,  2,  0,  5, -1,
+  1, -3,  4,  2,  2,  0,  2, -3,  1, -4,
+ -1,  1,  2,  2,  4,  1,  3, -1,  5,  2,
+  2,  0,  3, -1,  2, -3,  0,  1,  2,  2,
+  4,  0,  1, -5,  5,  1,  3,  0,  2, -1,
+  0, -2,  1,  2,  2,  2,  4,  1,  0,  0,
+  4,  2,  4,  1,  4, -1,  1, -4,  0,  1,
+  3,  1,  5,  1,  1, -2,  4,  0,  2,  0,
+  2, -1,  0, -2,  0,  1,  1,  1,  4,  2,
+  3, -2,  5,  4,  4,  0,  3,  0,  3, -4,
+  1,  2,  2,  0,  4,  1,  0, -3,  4,  2,
+  3, -1,  1, -1,  1, -4,  0,  2,  3,  1,
+  4,  1,  3,  0,  3,  3,  4,  1,  2,  0,
+  1, -3,  2,  2,  2,  1,  5,  0,  1, -4,
+  4,  1,  3, -2,  3, -1,  0, -2,  0,  2,
+  2,  0,  5,  1,  4, -1,  4,  3,  4,  1,
+  3,  0,  1, -4,  2,  0,  3,  1,  5,  0,
+  1, -5,  5,  2,  2,  0,  0,  0,  0, -4};
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/efb7ad9e5ddcddd48fb26cd8dc0ff2bc56d20aeb.svn-base b/jni/pjproject-android/.svn/pristine/ef/efb7ad9e5ddcddd48fb26cd8dc0ff2bc56d20aeb.svn-base
new file mode 100644
index 0000000..ebed3a3
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/efb7ad9e5ddcddd48fb26cd8dc0ff2bc56d20aeb.svn-base
@@ -0,0 +1,1603 @@
+/* $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 <pjmedia/sdp_neg.h>
+#include <pjmedia/sdp.h>
+#include <pjmedia/errno.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/ctype.h>
+#include <pj/array.h>
+
+/**
+ * This structure describes SDP media negotiator.
+ */
+struct pjmedia_sdp_neg
+{
+    pjmedia_sdp_neg_state state;	    /**< Negotiator state.	     */
+    pj_bool_t		  prefer_remote_codec_order;
+    pj_bool_t             answer_with_multiple_codecs;
+    pj_bool_t		  has_remote_answer;
+    pj_bool_t		  answer_was_remote;
+
+    pjmedia_sdp_session	*initial_sdp,	    /**< Initial local SDP	     */
+			*active_local_sdp,  /**< Currently active local SDP. */
+			*active_remote_sdp, /**< Currently active remote's.  */
+			*neg_local_sdp,	    /**< Temporary local SDP.	     */
+			*neg_remote_sdp;    /**< Temporary remote SDP.	     */
+};
+
+static const char *state_str[] = 
+{
+    "STATE_NULL",
+    "STATE_LOCAL_OFFER",
+    "STATE_REMOTE_OFFER",
+    "STATE_WAIT_NEGO",
+    "STATE_DONE",
+};
+
+/* Definition of customized SDP format negotiation callback */
+struct fmt_match_cb_t
+{
+    pj_str_t			    fmt_name;
+    pjmedia_sdp_neg_fmt_match_cb    cb;
+};
+
+/* Number of registered customized SDP format negotiation callbacks */
+static unsigned fmt_match_cb_cnt;
+
+/* The registered customized SDP format negotiation callbacks */
+static struct fmt_match_cb_t 
+	      fmt_match_cb[PJMEDIA_SDP_NEG_MAX_CUSTOM_FMT_NEG_CB];
+
+/* Redefining a very long identifier name, just for convenience */
+#define ALLOW_MODIFY_ANSWER PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER
+
+static pj_status_t custom_fmt_match( pj_pool_t *pool,
+				   const pj_str_t *fmt_name,
+				   pjmedia_sdp_media *offer,
+				   unsigned o_fmt_idx,
+				   pjmedia_sdp_media *answer,
+				   unsigned a_fmt_idx,
+				   unsigned option);
+
+
+/*
+ * Get string representation of negotiator state.
+ */
+PJ_DEF(const char*) pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_state state)
+{
+    if (state >=0 && state < (pjmedia_sdp_neg_state)PJ_ARRAY_SIZE(state_str))
+	return state_str[state];
+
+    return "<?UNKNOWN?>";
+}
+
+
+/*
+ * Create with local offer.
+ */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_create_w_local_offer( pj_pool_t *pool,
+				      const pjmedia_sdp_session *local,
+				      pjmedia_sdp_neg **p_neg)
+{
+    pjmedia_sdp_neg *neg;
+    pj_status_t status;
+
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && local && p_neg, PJ_EINVAL);
+
+    *p_neg = NULL;
+
+    /* Validate local offer. */
+    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(local))==PJ_SUCCESS, status);
+
+    /* Create and initialize negotiator. */
+    neg = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_neg);
+    PJ_ASSERT_RETURN(neg != NULL, PJ_ENOMEM);
+
+    neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;
+    neg->prefer_remote_codec_order = PJMEDIA_SDP_NEG_PREFER_REMOTE_CODEC_ORDER;
+    neg->answer_with_multiple_codecs = PJMEDIA_SDP_NEG_ANSWER_MULTIPLE_CODECS;
+    neg->initial_sdp = pjmedia_sdp_session_clone(pool, local);
+    neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
+
+    *p_neg = neg;
+    return PJ_SUCCESS;
+}
+
+/*
+ * Create with remote offer and initial local offer/answer.
+ */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool,
+				      const pjmedia_sdp_session *initial,
+				      const pjmedia_sdp_session *remote,
+				      pjmedia_sdp_neg **p_neg)
+{
+    pjmedia_sdp_neg *neg;
+    pj_status_t status;
+
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && remote && p_neg, PJ_EINVAL);
+
+    *p_neg = NULL;
+
+    /* Validate remote offer and initial answer */
+    status = pjmedia_sdp_validate2(remote, PJ_FALSE);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create and initialize negotiator. */
+    neg = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_neg);
+    PJ_ASSERT_RETURN(neg != NULL, PJ_ENOMEM);
+
+    neg->prefer_remote_codec_order = PJMEDIA_SDP_NEG_PREFER_REMOTE_CODEC_ORDER;
+    neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
+
+    if (initial) {
+	PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(initial))==PJ_SUCCESS, 
+			 status);
+
+	neg->initial_sdp = pjmedia_sdp_session_clone(pool, initial);
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, initial);
+
+	neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+
+    } else {
+	
+	neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER;
+
+    }
+
+    *p_neg = neg;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set codec order preference.
+ */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_set_prefer_remote_codec_order(
+						pjmedia_sdp_neg *neg,
+						pj_bool_t prefer_remote)
+{
+    PJ_ASSERT_RETURN(neg, PJ_EINVAL);
+    neg->prefer_remote_codec_order = prefer_remote;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Set multiple codec answering.
+ */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_set_answer_multiple_codecs(
+                        pjmedia_sdp_neg *neg,
+                        pj_bool_t answer_multiple)
+{
+    PJ_ASSERT_RETURN(neg, PJ_EINVAL);
+    neg->answer_with_multiple_codecs = answer_multiple;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get SDP negotiator state.
+ */
+PJ_DEF(pjmedia_sdp_neg_state) pjmedia_sdp_neg_get_state( pjmedia_sdp_neg *neg )
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(neg != NULL, PJMEDIA_SDP_NEG_STATE_NULL);
+    return neg->state;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_get_active_local( pjmedia_sdp_neg *neg,
+					const pjmedia_sdp_session **local)
+{
+    PJ_ASSERT_RETURN(neg && local, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->active_local_sdp, PJMEDIA_SDPNEG_ENOACTIVE);
+
+    *local = neg->active_local_sdp;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_get_active_remote( pjmedia_sdp_neg *neg,
+				   const pjmedia_sdp_session **remote)
+{
+    PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->active_remote_sdp, PJMEDIA_SDPNEG_ENOACTIVE);
+
+    *remote = neg->active_remote_sdp;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_bool_t) pjmedia_sdp_neg_was_answer_remote(pjmedia_sdp_neg *neg)
+{
+    PJ_ASSERT_RETURN(neg, PJ_FALSE);
+
+    return neg->answer_was_remote;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_get_neg_remote( pjmedia_sdp_neg *neg,
+				const pjmedia_sdp_session **remote)
+{
+    PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->neg_remote_sdp, PJMEDIA_SDPNEG_ENONEG);
+
+    *remote = neg->neg_remote_sdp;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg,
+			       const pjmedia_sdp_session **local)
+{
+    PJ_ASSERT_RETURN(neg && local, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->neg_local_sdp, PJMEDIA_SDPNEG_ENONEG);
+
+    *local = neg->neg_local_sdp;
+    return PJ_SUCCESS;
+}
+
+static pjmedia_sdp_media *sdp_media_clone_deactivate(
+				    pj_pool_t *pool,
+                                    const pjmedia_sdp_media *rem_med,
+                                    const pjmedia_sdp_media *local_med,
+                                    const pjmedia_sdp_session *local_sess)
+{
+    pjmedia_sdp_media *res;
+
+    res = pjmedia_sdp_media_clone_deactivate(pool, rem_med);
+    if (!res)
+	return NULL;
+
+    if (!res->conn && (!local_sess || !local_sess->conn)) {
+	if (local_med && local_med->conn)
+	    res->conn = pjmedia_sdp_conn_clone(pool, local_med->conn);
+	else {
+	    res->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
+	    res->conn->net_type = pj_str("IN");
+	    res->conn->addr_type = pj_str("IP4");
+	    res->conn->addr = pj_str("127.0.0.1");
+	}
+    }
+
+    return res;
+}
+
+/*
+ * Modify local SDP and wait for remote answer.
+ */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool,
+				    pjmedia_sdp_neg *neg,
+				    const pjmedia_sdp_session *local)
+{
+    return pjmedia_sdp_neg_modify_local_offer2(pool, neg, 0, local);
+}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
+                                    pj_pool_t *pool,
+				    pjmedia_sdp_neg *neg,
+                                    unsigned flags,
+				    const pjmedia_sdp_session *local)
+{
+    pjmedia_sdp_session *new_offer;
+    pjmedia_sdp_session *old_offer;
+    char media_used[PJMEDIA_MAX_SDP_MEDIA];
+    unsigned oi; /* old offer media index */
+    pj_status_t status;
+
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg && local, PJ_EINVAL);
+
+    /* Can only do this in STATE_DONE. */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_DONE, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* Validate the new offer */
+    status = pjmedia_sdp_validate(local);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Change state to STATE_LOCAL_OFFER */
+    neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;
+
+    /* Init vars */
+    pj_bzero(media_used, sizeof(media_used));
+    old_offer = neg->active_local_sdp;
+    new_offer = pjmedia_sdp_session_clone(pool, local);
+
+    /* RFC 3264 Section 8: When issuing an offer that modifies the session,
+     * the "o=" line of the new SDP MUST be identical to that in the
+     * previous SDP, except that the version in the origin field MUST
+     * increment by one from the previous SDP.
+     */
+    pj_strdup(pool, &new_offer->origin.user, &old_offer->origin.user);
+    new_offer->origin.id = old_offer->origin.id;
+    new_offer->origin.version = old_offer->origin.version + 1;
+    pj_strdup(pool, &new_offer->origin.net_type, &old_offer->origin.net_type);
+    pj_strdup(pool, &new_offer->origin.addr_type,&old_offer->origin.addr_type);
+    pj_strdup(pool, &new_offer->origin.addr, &old_offer->origin.addr);
+
+    if ((flags & PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE) == 0) {
+       /* Generating the new offer, in the case media lines doesn't match the
+        * active SDP (e.g. current/active SDP's have m=audio and m=video lines,
+        * and the new offer only has m=audio line), the negotiator will fix 
+        * the new offer by reordering and adding the missing media line with 
+        * port number set to zero.
+        */
+        for (oi = 0; oi < old_offer->media_count; ++oi) {
+	    pjmedia_sdp_media *om;
+	    pjmedia_sdp_media *nm;
+	    unsigned ni; /* new offer media index */
+	    pj_bool_t found = PJ_FALSE;
+
+	    om = old_offer->media[oi];
+	    for (ni = oi; ni < new_offer->media_count; ++ni) {
+	        nm = new_offer->media[ni];
+	        if (pj_strcmp(&nm->desc.media, &om->desc.media) == 0) {
+		    if (ni != oi) {
+		        /* The same media found but the position unmatched to
+                         * the old offer, so let's put this media in the right
+                         * place, and keep the order of the rest.
+		         */
+		        pj_array_insert(
+                            new_offer->media,		 /* array    */
+			    sizeof(new_offer->media[0]), /* elmt size*/
+			    ni,				 /* count    */
+		            oi,				 /* pos      */
+			    &nm);			 /* new elmt */
+		    }
+		    found = PJ_TRUE;
+		    break;
+	        }
+	    }
+	    if (!found) {
+	        pjmedia_sdp_media *m;
+
+	        m = sdp_media_clone_deactivate(pool, om, om, local);
+
+	        pj_array_insert(new_offer->media, sizeof(new_offer->media[0]),
+			        new_offer->media_count++, oi, &m);
+	    }
+        }
+    } else {
+        /* If media type change is allowed, the negotiator only needs to fix 
+         * the new offer by adding the missing media line(s) with port number
+         * set to zero.
+         */
+        for (oi = new_offer->media_count; oi < old_offer->media_count; ++oi) {
+            pjmedia_sdp_media *m;
+
+	    m = sdp_media_clone_deactivate(pool, old_offer->media[oi],
+                                           old_offer->media[oi], local);
+
+	    pj_array_insert(new_offer->media, sizeof(new_offer->media[0]),
+	                    new_offer->media_count++, oi, &m);
+
+        }
+    }
+
+    /* New_offer fixed */
+    neg->initial_sdp = new_offer;
+    neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, new_offer);
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_send_local_offer( pj_pool_t *pool,
+				  pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session **offer)
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(neg && offer, PJ_EINVAL);
+
+    *offer = NULL;
+
+    /* Can only do this in STATE_DONE or STATE_LOCAL_OFFER. */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_DONE ||
+		     neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    if (neg->state == PJMEDIA_SDP_NEG_STATE_DONE) {
+	/* If in STATE_DONE, set the active SDP as the offer. */
+	PJ_ASSERT_RETURN(neg->active_local_sdp, PJMEDIA_SDPNEG_ENOACTIVE);
+
+	neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER;
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, 
+						       neg->active_local_sdp);
+	*offer = neg->active_local_sdp;
+
+    } else {
+	/* We assume that we're in STATE_LOCAL_OFFER.
+	 * In this case set the neg_local_sdp as the offer.
+	 */
+	*offer = neg->neg_local_sdp;
+    }
+
+    
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_set_remote_answer( pj_pool_t *pool,
+				   pjmedia_sdp_neg *neg,
+				   const pjmedia_sdp_session *remote)
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL);
+
+    /* Can only do this in STATE_LOCAL_OFFER.
+     * If we haven't provided local offer, then rx_remote_offer() should
+     * be called instead of this function.
+     */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* We're ready to negotiate. */
+    neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+    neg->has_remote_answer = PJ_TRUE;
+    neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
+ 
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_set_remote_offer( pj_pool_t *pool,
+				  pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session *remote)
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL);
+
+    /* Can only do this in STATE_DONE.
+     * If we already provide local offer, then rx_remote_answer() should
+     * be called instead of this function.
+     */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_DONE, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* State now is STATE_REMOTE_OFFER. */
+    neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER;
+    neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_set_local_answer( pj_pool_t *pool,
+				  pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session *local)
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg && local, PJ_EINVAL);
+
+    /* Can only do this in STATE_REMOTE_OFFER.
+     * If we already provide local offer, then rx_remote_answer() should
+     * be called instead of this function.
+     */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* State now is STATE_WAIT_NEGO. */
+    neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+    if (local) {
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
+	if (neg->initial_sdp) {
+	    /* I don't think there is anything in RFC 3264 that mandates
+	     * answerer to place the same origin (and increment version)
+	     * in the answer, but probably it won't hurt either.
+	     * Note that the version will be incremented in 
+	     * pjmedia_sdp_neg_negotiate()
+	     */
+	    neg->neg_local_sdp->origin.id = neg->initial_sdp->origin.id;
+	} else {
+	    neg->initial_sdp = pjmedia_sdp_session_clone(pool, local);
+	}
+    } else {
+	PJ_ASSERT_RETURN(neg->initial_sdp, PJMEDIA_SDPNEG_ENOINITIAL);
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, neg->initial_sdp);
+    }
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_bool_t) pjmedia_sdp_neg_has_local_answer(pjmedia_sdp_neg *neg)
+{
+    pj_assert(neg && neg->state==PJMEDIA_SDP_NEG_STATE_WAIT_NEGO);
+    return !neg->has_remote_answer;
+}
+
+
+/* Swap string. */
+static void str_swap(pj_str_t *str1, pj_str_t *str2)
+{
+    pj_str_t tmp = *str1;
+    *str1 = *str2;
+    *str2 = tmp;
+}
+
+static void remove_all_media_directions(pjmedia_sdp_media *m)
+{
+    pjmedia_sdp_media_remove_all_attr(m, "inactive");
+    pjmedia_sdp_media_remove_all_attr(m, "sendrecv");
+    pjmedia_sdp_media_remove_all_attr(m, "sendonly");
+    pjmedia_sdp_media_remove_all_attr(m, "recvonly");
+}
+
+/* Update media direction based on peer's media direction */
+static void update_media_direction(pj_pool_t *pool,
+				   const pjmedia_sdp_media *remote,
+				   pjmedia_sdp_media *local)
+{
+    pjmedia_dir old_dir = PJMEDIA_DIR_ENCODING_DECODING,
+	        new_dir;
+
+    /* Get the media direction of local SDP */
+    if (pjmedia_sdp_media_find_attr2(local, "sendonly", NULL))
+	old_dir = PJMEDIA_DIR_ENCODING;
+    else if (pjmedia_sdp_media_find_attr2(local, "recvonly", NULL))
+	old_dir = PJMEDIA_DIR_DECODING;
+    else if (pjmedia_sdp_media_find_attr2(local, "inactive", NULL))
+	old_dir = PJMEDIA_DIR_NONE;
+
+    new_dir = old_dir;
+
+    /* Adjust local media direction based on remote media direction */
+    if (pjmedia_sdp_media_find_attr2(remote, "inactive", NULL) != NULL) {
+	/* If remote has "a=inactive", then local is inactive too */
+
+	new_dir = PJMEDIA_DIR_NONE;
+
+    } else if(pjmedia_sdp_media_find_attr2(remote, "sendonly", NULL) != NULL) {
+	/* If remote has "a=sendonly", then set local to "recvonly" if
+	 * it is currently "sendrecv". Otherwise if local is NOT "recvonly",
+	 * then set local direction to "inactive".
+	 */
+	switch (old_dir) {
+	case PJMEDIA_DIR_ENCODING_DECODING:
+	    new_dir = PJMEDIA_DIR_DECODING;
+	    break;
+	case PJMEDIA_DIR_DECODING:
+	    /* No change */
+	    break;
+	default:
+	    new_dir = PJMEDIA_DIR_NONE;
+	    break;
+	}
+
+    } else if(pjmedia_sdp_media_find_attr2(remote, "recvonly", NULL) != NULL) {
+	/* If remote has "a=recvonly", then set local to "sendonly" if
+	 * it is currently "sendrecv". Otherwise if local is NOT "sendonly",
+	 * then set local direction to "inactive"
+	 */
+    
+	switch (old_dir) {
+	case PJMEDIA_DIR_ENCODING_DECODING:
+	    new_dir = PJMEDIA_DIR_ENCODING;
+	    break;
+	case PJMEDIA_DIR_ENCODING:
+	    /* No change */
+	    break;
+	default:
+	    new_dir = PJMEDIA_DIR_NONE;
+	    break;
+	}
+
+    } else {
+	/* Remote indicates "sendrecv" capability. No change to local 
+	 * direction 
+	 */
+    }
+
+    if (new_dir != old_dir) {
+	pjmedia_sdp_attr *a = NULL;
+
+	remove_all_media_directions(local);
+
+	switch (new_dir) {
+	case PJMEDIA_DIR_NONE:
+	    a = pjmedia_sdp_attr_create(pool, "inactive", NULL);
+	    break;
+	case PJMEDIA_DIR_ENCODING:
+	    a = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
+	    break;
+	case PJMEDIA_DIR_DECODING:
+	    a = pjmedia_sdp_attr_create(pool, "recvonly", NULL);
+	    break;
+	default:
+	    /* sendrecv */
+	    break;
+	}
+	
+	if (a) {
+	    pjmedia_sdp_media_add_attr(local, a);
+	}
+    }
+}
+
+
+/* Update single local media description to after receiving answer
+ * from remote.
+ */
+static pj_status_t process_m_answer( pj_pool_t *pool,
+				     pjmedia_sdp_media *offer,
+				     pjmedia_sdp_media *answer,
+				     pj_bool_t allow_asym)
+{
+    unsigned i;
+
+    /* Check that the media type match our offer. */
+
+    if (pj_strcmp(&answer->desc.media, &offer->desc.media)!=0) {
+	/* The media type in the answer is different than the offer! */
+	return PJMEDIA_SDPNEG_EINVANSMEDIA;
+    }
+
+
+    /* Check that transport in the answer match our offer. */
+
+    /* At this point, transport type must be compatible, 
+     * the transport instance will do more validation later.
+     */
+    if (pjmedia_sdp_transport_cmp(&answer->desc.transport, 
+				  &offer->desc.transport) 
+	!= PJ_SUCCESS)
+    {
+	return PJMEDIA_SDPNEG_EINVANSTP;
+    }
+
+
+    /* Check if remote has rejected our offer */
+    if (answer->desc.port == 0) {
+	
+	/* Remote has rejected our offer. 
+	 * Deactivate our media too.
+	 */
+	pjmedia_sdp_media_deactivate(pool, offer);
+
+	/* Don't need to proceed */
+	return PJ_SUCCESS;
+    }
+
+    /* Ticket #1148: check if remote answer does not set port to zero when
+     * offered with port zero. Let's just tolerate it.
+     */
+    if (offer->desc.port == 0) {
+	/* Don't need to proceed */
+	return PJ_SUCCESS;
+    }
+
+    /* Process direction attributes */
+    update_media_direction(pool, answer, offer);
+ 
+    /* If asymetric media is allowed, then just check that remote answer has 
+     * codecs that are within the offer. 
+     *
+     * Otherwise if asymetric media is not allowed, then we will choose only
+     * one codec in our initial offer to match the answer.
+     */
+    if (allow_asym) {
+	for (i=0; i<answer->desc.fmt_count; ++i) {
+	    unsigned j;
+	    pj_str_t *rem_fmt = &answer->desc.fmt[i];
+
+	    for (j=0; j<offer->desc.fmt_count; ++j) {
+		if (pj_strcmp(rem_fmt, &answer->desc.fmt[j])==0)
+		    break;
+	    }
+
+	    if (j != offer->desc.fmt_count) {
+		/* Found at least one common codec. */
+		break;
+	    }
+	}
+
+	if (i == answer->desc.fmt_count) {
+	    /* No common codec in the answer! */
+	    return PJMEDIA_SDPNEG_EANSNOMEDIA;
+	}
+
+	PJ_TODO(CHECK_SDP_NEGOTIATION_WHEN_ASYMETRIC_MEDIA_IS_ALLOWED);
+
+    } else {
+	/* Offer format priority based on answer format index/priority */
+	unsigned offer_fmt_prior[PJMEDIA_MAX_SDP_FMT];
+
+	/* Remove all format in the offer that has no matching answer */
+	for (i=0; i<offer->desc.fmt_count;) {
+	    unsigned pt;
+	    pj_uint32_t j;
+	    pj_str_t *fmt = &offer->desc.fmt[i];
+	    
+
+	    /* Find matching answer */
+	    pt = pj_strtoul(fmt);
+
+	    if (pt < 96) {
+		for (j=0; j<answer->desc.fmt_count; ++j) {
+		    if (pj_strcmp(fmt, &answer->desc.fmt[j])==0)
+			break;
+		}
+	    } else {
+		/* This is dynamic payload type.
+		 * For dynamic payload type, we must look the rtpmap and
+		 * compare the encoding name.
+		 */
+		const pjmedia_sdp_attr *a;
+		pjmedia_sdp_rtpmap or_;
+
+		/* Get the rtpmap for the payload type in the offer. */
+		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
+		if (!a) {
+		    pj_assert(!"Bug! Offer should have been validated");
+		    return PJ_EBUG;
+		}
+		pjmedia_sdp_attr_get_rtpmap(a, &or_);
+
+		/* Find paylaod in answer SDP with matching 
+		 * encoding name and clock rate.
+		 */
+		for (j=0; j<answer->desc.fmt_count; ++j) {
+		    a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
+						     &answer->desc.fmt[j]);
+		    if (a) {
+			pjmedia_sdp_rtpmap ar;
+			pjmedia_sdp_attr_get_rtpmap(a, &ar);
+
+			/* See if encoding name, clock rate, and channel
+			 * count match 
+			 */
+			if (!pj_stricmp(&or_.enc_name, &ar.enc_name) &&
+			    or_.clock_rate == ar.clock_rate &&
+			    (pj_stricmp(&or_.param, &ar.param)==0 ||
+			     (ar.param.slen==1 && *ar.param.ptr=='1')))
+			{
+			    /* Call custom format matching callbacks */
+			    if (custom_fmt_match(pool, &or_.enc_name,
+						 offer, i, answer, j, 0) ==
+				PJ_SUCCESS)
+			    {
+				/* Match! */
+				break;
+			    }
+			}
+		    }
+		}
+	    }
+
+	    if (j == answer->desc.fmt_count) {
+		/* This format has no matching answer.
+		 * Remove it from our offer.
+		 */
+		pjmedia_sdp_attr *a;
+
+		/* Remove rtpmap associated with this format */
+		a = pjmedia_sdp_media_find_attr2(offer, "rtpmap", fmt);
+		if (a)
+		    pjmedia_sdp_media_remove_attr(offer, a);
+
+		/* Remove fmtp associated with this format */
+		a = pjmedia_sdp_media_find_attr2(offer, "fmtp", fmt);
+		if (a)
+		    pjmedia_sdp_media_remove_attr(offer, a);
+
+		/* Remove this format from offer's array */
+		pj_array_erase(offer->desc.fmt, sizeof(offer->desc.fmt[0]),
+			       offer->desc.fmt_count, i);
+		--offer->desc.fmt_count;
+
+	    } else {
+		offer_fmt_prior[i] = j;
+		++i;
+	    }
+	}
+
+	if (0 == offer->desc.fmt_count) {
+	    /* No common codec in the answer! */
+	    return PJMEDIA_SDPNEG_EANSNOMEDIA;
+	}
+
+	/* Post process:
+	 * - Resort offer formats so the order match to the answer.
+	 * - Remove answer formats that unmatches to the offer.
+	 */
+	
+	/* Resort offer formats */
+	for (i=0; i<offer->desc.fmt_count; ++i) {
+	    unsigned j;
+	    for (j=i+1; j<offer->desc.fmt_count; ++j) {
+		if (offer_fmt_prior[i] > offer_fmt_prior[j]) {
+		    unsigned tmp = offer_fmt_prior[i];
+		    offer_fmt_prior[i] = offer_fmt_prior[j];
+		    offer_fmt_prior[j] = tmp;
+		    str_swap(&offer->desc.fmt[i], &offer->desc.fmt[j]);
+		}
+	    }
+	}
+
+	/* Remove unmatched answer formats */
+	{
+	    unsigned del_cnt = 0;
+	    for (i=0; i<answer->desc.fmt_count;) {
+		/* The offer is ordered now, also the offer_fmt_prior */
+		if (i >= offer->desc.fmt_count || 
+		    offer_fmt_prior[i]-del_cnt != i)
+		{
+		    pj_str_t *fmt = &answer->desc.fmt[i];
+		    pjmedia_sdp_attr *a;
+
+		    /* Remove rtpmap associated with this format */
+		    a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", fmt);
+		    if (a)
+			pjmedia_sdp_media_remove_attr(answer, a);
+
+		    /* Remove fmtp associated with this format */
+		    a = pjmedia_sdp_media_find_attr2(answer, "fmtp", fmt);
+		    if (a)
+			pjmedia_sdp_media_remove_attr(answer, a);
+
+		    /* Remove this format from answer's array */
+		    pj_array_erase(answer->desc.fmt, 
+				   sizeof(answer->desc.fmt[0]),
+				   answer->desc.fmt_count, i);
+		    --answer->desc.fmt_count;
+
+		    ++del_cnt;
+		} else {
+		    ++i;
+		}
+	    }
+	}
+    }
+
+    /* Looks okay */
+    return PJ_SUCCESS;
+}
+
+
+/* Update local media session (offer) to create active local session
+ * after receiving remote answer.
+ */
+static pj_status_t process_answer(pj_pool_t *pool,
+				  pjmedia_sdp_session *offer,
+				  pjmedia_sdp_session *answer,
+				  pj_bool_t allow_asym,
+				  pjmedia_sdp_session **p_active)
+{
+    unsigned omi = 0; /* Offer media index */
+    unsigned ami = 0; /* Answer media index */
+    pj_bool_t has_active = PJ_FALSE;
+    pj_status_t status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(pool && offer && answer && p_active, PJ_EINVAL);
+
+    /* Check that media count match between offer and answer */
+    // Ticket #527, different media count is allowed for more interoperability,
+    // however, the media order must be same between offer and answer.
+    // if (offer->media_count != answer->media_count)
+    //	   return PJMEDIA_SDPNEG_EMISMEDIA;
+
+    /* Now update each media line in the offer with the answer. */
+    for (; omi<offer->media_count; ++omi) {
+	if (ami == answer->media_count) {
+	    /* The answer has less media than the offer */
+	    pjmedia_sdp_media *am;
+
+	    /* Generate matching-but-disabled-media for the answer */
+	    am = sdp_media_clone_deactivate(pool, offer->media[omi],
+	                                    offer->media[omi], offer);
+	    answer->media[answer->media_count++] = am;
+	    ++ami;
+
+	    /* Deactivate our media offer too */
+	    pjmedia_sdp_media_deactivate(pool, offer->media[omi]);
+
+	    /* No answer media to be negotiated */
+	    continue;
+	}
+
+	status = process_m_answer(pool, offer->media[omi], answer->media[ami],
+				  allow_asym);
+
+	/* If media type is mismatched, just disable the media. */
+	if (status == PJMEDIA_SDPNEG_EINVANSMEDIA) {
+	    pjmedia_sdp_media_deactivate(pool, offer->media[omi]);
+	    continue;
+	}
+	/* No common format in the answer media. */
+	else if (status == PJMEDIA_SDPNEG_EANSNOMEDIA) {
+	    pjmedia_sdp_media_deactivate(pool, offer->media[omi]);
+	    pjmedia_sdp_media_deactivate(pool, answer->media[ami]);
+	} 
+	/* Return the error code, for other errors. */
+	else if (status != PJ_SUCCESS) {
+	    return status;
+	}
+
+	if (offer->media[omi]->desc.port != 0)
+	    has_active = PJ_TRUE;
+
+	++ami;
+    }
+
+    *p_active = offer;
+
+    return has_active ? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA;
+}
+
+
+/* Internal function to rewrite the format string in SDP attribute rtpmap
+ * and fmtp.
+ */
+PJ_INLINE(void) rewrite_pt(pj_pool_t *pool, pj_str_t *attr_val,
+			   const pj_str_t *old_pt, const pj_str_t *new_pt)
+{
+    int len_diff = (int)(new_pt->slen - old_pt->slen);
+
+    /* Note that attribute value should be null-terminated. */
+    if (len_diff > 0) {
+	pj_str_t new_val;
+	new_val.ptr = (char*)pj_pool_alloc(pool, attr_val->slen+len_diff+1);
+	new_val.slen = attr_val->slen + len_diff;
+	pj_memcpy(new_val.ptr + len_diff, attr_val->ptr, attr_val->slen + 1);
+	*attr_val = new_val;
+    } else if (len_diff < 0) {
+	attr_val->slen += len_diff;
+	pj_memmove(attr_val->ptr, attr_val->ptr - len_diff,
+		   attr_val->slen + 1);
+    }
+    pj_memcpy(attr_val->ptr, new_pt->ptr, new_pt->slen);
+}
+
+
+/* Internal function to apply symmetric PT for the local answer. */
+static void apply_answer_symmetric_pt(pj_pool_t *pool,
+				      pjmedia_sdp_media *answer,
+				      unsigned pt_cnt,
+				      const pj_str_t pt_offer[],
+				      const pj_str_t pt_answer[])
+{
+    pjmedia_sdp_attr *a_tmp[PJMEDIA_MAX_SDP_ATTR];
+    unsigned i, a_tmp_cnt = 0;
+
+    /* Rewrite the payload types in the answer if different to
+     * the ones in the offer.
+     */
+    for (i = 0; i < pt_cnt; ++i) {
+	pjmedia_sdp_attr *a;
+
+	/* Skip if the PTs are the same already, e.g: static PT. */
+	if (pj_strcmp(&pt_answer[i], &pt_offer[i]) == 0)
+	    continue;
+
+	/* Rewrite payload type in the answer to match to the offer */
+	pj_strdup(pool, &answer->desc.fmt[i], &pt_offer[i]);
+
+	/* Also update payload type in rtpmap */
+	a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", &pt_answer[i]);
+	if (a) {
+	    rewrite_pt(pool, &a->value, &pt_answer[i], &pt_offer[i]);
+	    /* Temporarily remove the attribute in case the new payload
+	     * type is being used by another format in the media.
+	     */
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	    a_tmp[a_tmp_cnt++] = a;
+	}
+
+	/* Also update payload type in fmtp */
+	a = pjmedia_sdp_media_find_attr2(answer, "fmtp", &pt_answer[i]);
+	if (a) {
+	    rewrite_pt(pool, &a->value, &pt_answer[i], &pt_offer[i]);
+	    /* Temporarily remove the attribute in case the new payload
+	     * type is being used by another format in the media.
+	     */
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	    a_tmp[a_tmp_cnt++] = a;
+	}
+    }
+
+    /* Return back 'rtpmap' and 'fmtp' attributes */
+    for (i = 0; i < a_tmp_cnt; ++i)
+	pjmedia_sdp_media_add_attr(answer, a_tmp[i]);
+}
+
+
+/* Try to match offer with answer. */
+static pj_status_t match_offer(pj_pool_t *pool,
+			       pj_bool_t prefer_remote_codec_order,
+                               pj_bool_t answer_with_multiple_codecs,
+			       const pjmedia_sdp_media *offer,
+			       const pjmedia_sdp_media *preanswer,
+			       const pjmedia_sdp_session *preanswer_sdp,
+			       pjmedia_sdp_media **p_answer)
+{
+    unsigned i;
+    pj_bool_t master_has_codec = 0,
+	      master_has_telephone_event = 0,
+	      master_has_other = 0,
+	      found_matching_codec = 0,
+	      found_matching_telephone_event = 0,
+	      found_matching_other = 0;
+    unsigned pt_answer_count = 0;
+    pj_str_t pt_answer[PJMEDIA_MAX_SDP_FMT];
+    pj_str_t pt_offer[PJMEDIA_MAX_SDP_FMT];
+    pjmedia_sdp_media *answer;
+    const pjmedia_sdp_media *master, *slave;
+
+    /* If offer has zero port, just clone the offer */
+    if (offer->desc.port == 0) {
+	answer = sdp_media_clone_deactivate(pool, offer, preanswer,
+					    preanswer_sdp);
+	*p_answer = answer;
+	return PJ_SUCCESS;
+    }
+
+    /* If the preanswer define zero port, this media is being rejected,
+     * just clone the preanswer.
+     */
+    if (preanswer->desc.port == 0) {
+	answer = pjmedia_sdp_media_clone(pool, preanswer);
+	*p_answer = answer;
+	return PJ_SUCCESS;
+    }
+
+    /* Set master/slave negotiator based on prefer_remote_codec_order. */
+    if (prefer_remote_codec_order) {
+	master = offer;
+	slave  = preanswer;
+    } else {
+	master = preanswer;
+	slave  = offer;
+    }
+    
+    /* With the addition of telephone-event and dodgy MS RTC SDP, 
+     * the answer generation algorithm looks really shitty...
+     */
+    for (i=0; i<master->desc.fmt_count; ++i) {
+	unsigned j;
+	
+	if (pj_isdigit(*master->desc.fmt[i].ptr)) {
+	    /* This is normal/standard payload type, where it's identified
+	     * by payload number.
+	     */
+	    unsigned pt;
+
+	    pt = pj_strtoul(&master->desc.fmt[i]);
+	    
+	    if (pt < 96) {
+		/* For static payload type, it's enough to compare just
+		 * the payload number.
+		 */
+
+		master_has_codec = 1;
+
+		/* We just need to select one codec if not allowing multiple.
+		 * Continue if we have selected matching codec for previous 
+		 * payload.
+		 */
+		if (!answer_with_multiple_codecs && found_matching_codec)
+		    continue;
+
+		/* Find matching codec in local descriptor. */
+		for (j=0; j<slave->desc.fmt_count; ++j) {
+		    unsigned p;
+		    p = pj_strtoul(&slave->desc.fmt[j]);
+		    if (p == pt && pj_isdigit(*slave->desc.fmt[j].ptr)) {
+			found_matching_codec = 1;
+			pt_offer[pt_answer_count] = slave->desc.fmt[j];
+			pt_answer[pt_answer_count++] = slave->desc.fmt[j];
+			break;
+		    }
+		}
+
+	    } else {
+		/* This is dynamic payload type.
+		 * For dynamic payload type, we must look the rtpmap and
+		 * compare the encoding name.
+		 */
+		const pjmedia_sdp_attr *a;
+		pjmedia_sdp_rtpmap or_;
+		pj_bool_t is_codec;
+
+		/* Get the rtpmap for the payload type in the master. */
+		a = pjmedia_sdp_media_find_attr2(master, "rtpmap", 
+						 &master->desc.fmt[i]);
+		if (!a) {
+		    pj_assert(!"Bug! Offer should have been validated");
+		    return PJMEDIA_SDP_EMISSINGRTPMAP;
+		}
+		pjmedia_sdp_attr_get_rtpmap(a, &or_);
+
+		if (!pj_stricmp2(&or_.enc_name, "telephone-event")) {
+		    master_has_telephone_event = 1;
+		    if (found_matching_telephone_event)
+			continue;
+		    is_codec = 0;
+		} else {
+		    master_has_codec = 1;
+		    if (!answer_with_multiple_codecs && found_matching_codec)
+			continue;
+		    is_codec = 1;
+		}
+		
+		/* Find paylaod in our initial SDP with matching 
+		 * encoding name and clock rate.
+		 */
+		for (j=0; j<slave->desc.fmt_count; ++j) {
+		    a = pjmedia_sdp_media_find_attr2(slave, "rtpmap", 
+						     &slave->desc.fmt[j]);
+		    if (a) {
+			pjmedia_sdp_rtpmap lr;
+			pjmedia_sdp_attr_get_rtpmap(a, &lr);
+
+			/* See if encoding name, clock rate, and
+			 * channel count  match 
+			 */
+			if (!pj_stricmp(&or_.enc_name, &lr.enc_name) &&
+			    or_.clock_rate == lr.clock_rate &&
+			    (pj_stricmp(&or_.param, &lr.param)==0 ||
+			     (lr.param.slen==0 && or_.param.slen==1 && 
+						 *or_.param.ptr=='1') || 
+			     (or_.param.slen==0 && lr.param.slen==1 && 
+						  *lr.param.ptr=='1'))) 
+			{
+			    /* Match! */
+			    if (is_codec) {
+				pjmedia_sdp_media *o, *a;
+				unsigned o_fmt_idx, a_fmt_idx;
+
+				o = (pjmedia_sdp_media*)offer;
+				a = (pjmedia_sdp_media*)preanswer;
+				o_fmt_idx = prefer_remote_codec_order? i:j;
+				a_fmt_idx = prefer_remote_codec_order? j:i;
+
+				/* Call custom format matching callbacks */
+				if (custom_fmt_match(pool, &or_.enc_name,
+						     o, o_fmt_idx,
+						     a, a_fmt_idx,
+						     ALLOW_MODIFY_ANSWER) !=
+				    PJ_SUCCESS)
+				{
+				    continue;
+				}
+				found_matching_codec = 1;
+			    } else {
+				found_matching_telephone_event = 1;
+			    }
+
+			    pt_offer[pt_answer_count] = 
+						prefer_remote_codec_order?
+						offer->desc.fmt[i]:
+						offer->desc.fmt[j];
+			    pt_answer[pt_answer_count++] = 
+						prefer_remote_codec_order? 
+						preanswer->desc.fmt[j]:
+						preanswer->desc.fmt[i];
+			    break;
+			}
+		    }
+		}
+	    }
+
+	} else {
+	    /* This is a non-standard, brain damaged SDP where the payload
+	     * type is non-numeric. It exists e.g. in Microsoft RTC based
+	     * UA, to indicate instant messaging capability.
+	     * Example:
+	     *	- m=x-ms-message 5060 sip null
+	     */
+	    master_has_other = 1;
+	    if (found_matching_other)
+		continue;
+
+	    for (j=0; j<slave->desc.fmt_count; ++j) {
+		if (!pj_strcmp(&master->desc.fmt[i], &slave->desc.fmt[j])) {
+		    /* Match */
+		    found_matching_other = 1;
+		    pt_offer[pt_answer_count] = prefer_remote_codec_order?
+						offer->desc.fmt[i]:
+						offer->desc.fmt[j];
+		    pt_answer[pt_answer_count++] = prefer_remote_codec_order? 
+						   preanswer->desc.fmt[j]:
+						   preanswer->desc.fmt[i];
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* See if all types of master can be matched. */
+    if (master_has_codec && !found_matching_codec) {
+	return PJMEDIA_SDPNEG_NOANSCODEC;
+    }
+
+    /* If this comment is removed, negotiation will fail if remote has offered
+       telephone-event and local is not configured with telephone-event
+
+    if (offer_has_telephone_event && !found_matching_telephone_event) {
+	return PJMEDIA_SDPNEG_NOANSTELEVENT;
+    }
+    */
+
+    if (master_has_other && !found_matching_other) {
+	return PJMEDIA_SDPNEG_NOANSUNKNOWN;
+    }
+
+    /* Seems like everything is in order.
+     * Build the answer by cloning from preanswer, but rearrange the payload
+     * to suit the offer.
+     */
+    answer = pjmedia_sdp_media_clone(pool, preanswer);
+    for (i=0; i<pt_answer_count; ++i) {
+	unsigned j;
+	for (j=i; j<answer->desc.fmt_count; ++j) {
+	    if (!pj_strcmp(&answer->desc.fmt[j], &pt_answer[i]))
+		break;
+	}
+	pj_assert(j != answer->desc.fmt_count);
+	str_swap(&answer->desc.fmt[i], &answer->desc.fmt[j]);
+    }
+    
+    /* Remove unwanted local formats. */
+    for (i=pt_answer_count; i<answer->desc.fmt_count; ++i) {
+	pjmedia_sdp_attr *a;
+
+	/* Remove rtpmap for this format */
+	a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
+					 &answer->desc.fmt[i]);
+	if (a) {
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	}
+
+	/* Remove fmtp for this format */
+	a = pjmedia_sdp_media_find_attr2(answer, "fmtp", 
+					 &answer->desc.fmt[i]);
+	if (a) {
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	}
+    }
+    answer->desc.fmt_count = pt_answer_count;
+
+#if PJMEDIA_SDP_NEG_ANSWER_SYMMETRIC_PT
+    apply_answer_symmetric_pt(pool, answer, pt_answer_count,
+			      pt_offer, pt_answer);
+#endif
+
+    /* Update media direction. */
+    update_media_direction(pool, offer, answer);
+
+    *p_answer = answer;
+    return PJ_SUCCESS;
+}
+
+/* Create complete answer for remote's offer. */
+static pj_status_t create_answer( pj_pool_t *pool,
+				  pj_bool_t prefer_remote_codec_order,
+                                  pj_bool_t answer_with_multiple_codecs,
+				  const pjmedia_sdp_session *initial,
+				  const pjmedia_sdp_session *offer,
+				  pjmedia_sdp_session **p_answer)
+{
+    pj_status_t status = PJMEDIA_SDPNEG_ENOMEDIA;
+    pj_bool_t has_active = PJ_FALSE;
+    pjmedia_sdp_session *answer;
+    char media_used[PJMEDIA_MAX_SDP_MEDIA];
+    unsigned i;
+
+    /* Validate remote offer. 
+     * This should have been validated before.
+     */
+    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(offer))==PJ_SUCCESS, status);
+
+    /* Create initial answer by duplicating initial SDP,
+     * but clear all media lines. The media lines will be filled up later.
+     */
+    answer = pjmedia_sdp_session_clone(pool, initial);
+    PJ_ASSERT_RETURN(answer != NULL, PJ_ENOMEM);
+
+    answer->media_count = 0;
+
+    pj_bzero(media_used, sizeof(media_used));
+
+    /* For each media line, create our answer based on our initial
+     * capability.
+     */
+    for (i=0; i<offer->media_count; ++i) {
+	const pjmedia_sdp_media *om;	/* offer */
+	const pjmedia_sdp_media *im;	/* initial media */
+	pjmedia_sdp_media *am = NULL;	/* answer/result */
+	unsigned j;
+
+	om = offer->media[i];
+
+	/* Find media description in our initial capability that matches
+	 * the media type and transport type of offer's media, has
+	 * matching codec, and has not been used to answer other offer.
+	 */
+	for (im=NULL, j=0; j<initial->media_count; ++j) {
+	    im = initial->media[j];
+	    if (pj_strcmp(&om->desc.media, &im->desc.media)==0 &&
+		pj_strcmp(&om->desc.transport, &im->desc.transport)==0 &&
+		media_used[j] == 0)
+	    {
+                pj_status_t status2;
+
+		/* See if it has matching codec. */
+		status2 = match_offer(pool, prefer_remote_codec_order,
+                                      answer_with_multiple_codecs,
+				      om, im, initial, &am);
+		if (status2 == PJ_SUCCESS) {
+		    /* Mark media as used. */
+		    media_used[j] = 1;
+		    break;
+                } else {
+                    status = status2;
+                }
+	    }
+	}
+
+	if (j==initial->media_count) {
+	    /* No matching media.
+	     * Reject the offer by setting the port to zero in the answer.
+	     */
+	    /* For simplicity in the construction of the answer, we'll
+	     * just clone the media from the offer. Anyway receiver will
+	     * ignore anything in the media once it sees that the port
+	     * number is zero.
+	     */
+	    am = sdp_media_clone_deactivate(pool, om, om, answer);
+	} else {
+	    /* The answer is in am */
+	    pj_assert(am != NULL);
+	}
+
+	/* Add the media answer */
+	answer->media[answer->media_count++] = am;
+
+	/* Check if this media is active.*/
+	if (am->desc.port != 0)
+	    has_active = PJ_TRUE;
+    }
+
+    *p_answer = answer;
+
+    return has_active ? PJ_SUCCESS : status;
+}
+
+/* Cancel offer */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_cancel_offer(pjmedia_sdp_neg *neg)
+{
+    PJ_ASSERT_RETURN(neg, PJ_EINVAL);
+
+    /* Must be in LOCAL_OFFER state. */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
+		     neg->state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER,
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* Clear temporary SDP */
+    neg->neg_local_sdp = neg->neg_remote_sdp = NULL;
+    neg->has_remote_answer = PJ_FALSE;
+
+    if (neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
+	/* Increment next version number. This happens if for example
+	 * the reinvite offer is rejected by 488. If we don't increment
+	 * the version here, the next offer will have the same version.
+	 */
+	neg->active_local_sdp->origin.version++;
+    }
+
+    /* Reset state to done */
+    neg->state = PJMEDIA_SDP_NEG_STATE_DONE;
+
+    return PJ_SUCCESS;
+}
+
+
+/* The best bit: SDP negotiation function! */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool,
+					       pjmedia_sdp_neg *neg,
+					       pj_bool_t allow_asym)
+{
+    pj_status_t status;
+
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg, PJ_EINVAL);
+
+    /* Must be in STATE_WAIT_NEGO state. */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* Must have remote offer. */
+    PJ_ASSERT_RETURN(neg->neg_remote_sdp, PJ_EBUG);
+
+    if (neg->has_remote_answer) {
+	pjmedia_sdp_session *active;
+	status = process_answer(pool, neg->neg_local_sdp, neg->neg_remote_sdp,
+			        allow_asym, &active);
+	if (status == PJ_SUCCESS) {
+	    /* Only update active SDPs when negotiation is successfull */
+	    neg->active_local_sdp = active;
+	    neg->active_remote_sdp = neg->neg_remote_sdp;
+	}
+    } else {
+	pjmedia_sdp_session *answer = NULL;
+
+	status = create_answer(pool, neg->prefer_remote_codec_order,
+                               neg->answer_with_multiple_codecs,
+			       neg->neg_local_sdp, neg->neg_remote_sdp,
+			       &answer);
+	if (status == PJ_SUCCESS) {
+	    pj_uint32_t active_ver;
+
+	    if (neg->active_local_sdp)
+		active_ver = neg->active_local_sdp->origin.version;
+	    else
+		active_ver = neg->initial_sdp->origin.version;
+
+	    /* Only update active SDPs when negotiation is successfull */
+	    neg->active_local_sdp = answer;
+	    neg->active_remote_sdp = neg->neg_remote_sdp;
+
+	    /* Increment SDP version */
+	    neg->active_local_sdp->origin.version = ++active_ver;
+	}
+    }
+
+    /* State is DONE regardless */
+    neg->state = PJMEDIA_SDP_NEG_STATE_DONE;
+
+    /* Save state */
+    neg->answer_was_remote = neg->has_remote_answer;
+
+    /* Clear temporary SDP */
+    neg->neg_local_sdp = neg->neg_remote_sdp = NULL;
+    neg->has_remote_answer = PJ_FALSE;
+
+    return status;
+}
+
+
+static pj_status_t custom_fmt_match(pj_pool_t *pool,
+				    const pj_str_t *fmt_name,
+				    pjmedia_sdp_media *offer,
+				    unsigned o_fmt_idx,
+				    pjmedia_sdp_media *answer,
+				    unsigned a_fmt_idx,
+				    unsigned option)
+{
+    unsigned i;
+
+    for (i = 0; i < fmt_match_cb_cnt; ++i) {
+	if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0) {
+	    pj_assert(fmt_match_cb[i].cb);
+	    return (*fmt_match_cb[i].cb)(pool, offer, o_fmt_idx,
+					 answer, a_fmt_idx,
+					 option);
+	}
+    }
+
+    /* Not customized format matching found, should be matched */
+    return PJ_SUCCESS;
+}
+
+/* Register customized SDP format negotiation callback function. */
+PJ_DECL(pj_status_t) pjmedia_sdp_neg_register_fmt_match_cb(
+					const pj_str_t *fmt_name,
+					pjmedia_sdp_neg_fmt_match_cb cb)
+{
+    struct fmt_match_cb_t *f = NULL;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(fmt_name, PJ_EINVAL);
+
+    /* Check if the callback for the format name has been registered */
+    for (i = 0; i < fmt_match_cb_cnt; ++i) {
+	if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0)
+	    break;
+    }
+
+    /* Unregistration */
+    
+    if (cb == NULL) {
+	if (i == fmt_match_cb_cnt)
+	    return PJ_ENOTFOUND;
+
+	pj_array_erase(fmt_match_cb, sizeof(fmt_match_cb[0]),
+		       fmt_match_cb_cnt, i);
+	fmt_match_cb_cnt--;
+
+	return PJ_SUCCESS;
+    }
+
+    /* Registration */
+
+    if (i < fmt_match_cb_cnt) {
+	/* The same format name has been registered before */
+	if (cb != fmt_match_cb[i].cb)
+	    return PJ_EEXISTS;
+	else
+	    return PJ_SUCCESS;
+    }
+
+    if (fmt_match_cb_cnt >= PJ_ARRAY_SIZE(fmt_match_cb))
+	return PJ_ETOOMANY;
+
+    f = &fmt_match_cb[fmt_match_cb_cnt++];
+    f->fmt_name = *fmt_name;
+    f->cb = cb;
+
+    return PJ_SUCCESS;
+}
+
+
+/* Match format in the SDP media offer and answer. */
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_fmt_match(pj_pool_t *pool,
+					      pjmedia_sdp_media *offer,
+					      unsigned o_fmt_idx,
+					      pjmedia_sdp_media *answer,
+					      unsigned a_fmt_idx,
+					      unsigned option)
+{
+    const pjmedia_sdp_attr *attr;
+    pjmedia_sdp_rtpmap o_rtpmap, a_rtpmap;
+    unsigned o_pt;
+    unsigned a_pt;
+
+    o_pt = pj_strtoul(&offer->desc.fmt[o_fmt_idx]);
+    a_pt = pj_strtoul(&answer->desc.fmt[a_fmt_idx]);
+
+    if (o_pt < 96 || a_pt < 96) {
+	if (o_pt == a_pt)
+	    return PJ_SUCCESS;
+	else
+	    return PJMEDIA_SDP_EFORMATNOTEQUAL;
+    }
+
+    /* Get the format rtpmap from the offer. */
+    attr = pjmedia_sdp_media_find_attr2(offer, "rtpmap", 
+					&offer->desc.fmt[o_fmt_idx]);
+    if (!attr) {
+	pj_assert(!"Bug! Offer haven't been validated");
+	return PJ_EBUG;
+    }
+    pjmedia_sdp_attr_get_rtpmap(attr, &o_rtpmap);
+
+    /* Get the format rtpmap from the answer. */
+    attr = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 
+					&answer->desc.fmt[a_fmt_idx]);
+    if (!attr) {
+	pj_assert(!"Bug! Answer haven't been validated");
+	return PJ_EBUG;
+    }
+    pjmedia_sdp_attr_get_rtpmap(attr, &a_rtpmap);
+
+    if (pj_stricmp(&o_rtpmap.enc_name, &a_rtpmap.enc_name) != 0 ||
+	o_rtpmap.clock_rate != a_rtpmap.clock_rate)
+    {
+	return PJMEDIA_SDP_EFORMATNOTEQUAL;
+    }
+
+    return custom_fmt_match(pool, &o_rtpmap.enc_name,
+			    offer, o_fmt_idx, answer, a_fmt_idx, option);
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/efdfc668e2626957bc7e0579fc98fbb68fc47d04.svn-base b/jni/pjproject-android/.svn/pristine/ef/efdfc668e2626957bc7e0579fc98fbb68fc47d04.svn-base
new file mode 100644
index 0000000..43dd162
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/efdfc668e2626957bc7e0579fc98fbb68fc47d04.svn-base
@@ -0,0 +1,194 @@
+/* $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/ioqueue.h>
+#include <pj/os.h>
+#include <pj/log.h>
+#include <pj/list.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/sock.h>
+#include <pj/errno.h>
+
+#define THIS_FILE   "ioqueue"
+
+#define PJ_IOQUEUE_IS_READ_OP(op)   \
+	((op & PJ_IOQUEUE_OP_READ)  || (op & PJ_IOQUEUE_OP_RECV_FROM))
+#define PJ_IOQUEUE_IS_WRITE_OP(op)  \
+	((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
+
+
+#if PJ_HAS_TCP
+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	(op & PJ_IOQUEUE_OP_ACCEPT)
+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	(op & PJ_IOQUEUE_OP_CONNECT)
+#else
+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	0
+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	0
+#endif
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+#  define VALIDATE_FD_SET		1
+#else
+#  define VALIDATE_FD_SET		0
+#endif
+
+struct pj_ioqueue_key_t
+{
+    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
+    pj_sock_t		    fd;
+    pj_ioqueue_operation_e  op;
+    void		   *user_data;
+    pj_ioqueue_callback	    cb;
+};
+
+struct pj_ioqueue_t
+{
+};
+
+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
+				       pj_size_t max_fd,
+				       int max_threads,
+				       pj_ioqueue_t **ptr_ioqueue)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
+					 pj_lock_t *lock,
+					 pj_bool_t auto_delete )
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
+					      pj_ioqueue_t *ioque,
+					      pj_sock_t sock,
+					      void *user_data,
+					      const pj_ioqueue_callback *cb,
+					      pj_ioqueue_key_t **ptr_key)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
+					   pj_ioqueue_key_t *key)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
+{
+    return NULL;
+}
+
+
+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     void *buffer,
+				     pj_size_t buflen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     void *buffer,
+				     pj_size_t buflen,
+				     unsigned flags)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
+					 pj_ioqueue_key_t *key,
+					 void *buffer,
+					 pj_size_t buflen,
+					 unsigned flags,
+					 pj_sockaddr_t *addr,
+					 int *addrlen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,
+				      pj_ioqueue_key_t *key,
+				      const void *data,
+				      pj_size_t datalen)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,
+				     pj_ioqueue_key_t *key,
+				     const void *data,
+				     pj_size_t datalen,
+				     unsigned flags)
+{
+    return -1;
+}
+
+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
+				       pj_ioqueue_key_t *key,
+				       const void *data,
+				       pj_size_t datalen,
+				       unsigned flags,
+				       const pj_sockaddr_t *addr,
+				       int addrlen)
+{
+    return -1;
+}
+
+#if PJ_HAS_TCP
+/*
+ * Initiate overlapped accept() operation.
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
+				       pj_ioqueue_key_t *key,
+				       pj_sock_t *new_sock,
+				       pj_sockaddr_t *local,
+				       pj_sockaddr_t *remote,
+				      int *addrlen)
+{
+    return -1;
+}
+
+/*
+ * Initiate overlapped connect() operation (well, it's non-blocking actually,
+ * since there's no overlapped version of connect()).
+ */
+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
+					pj_ioqueue_key_t *key,
+					const pj_sockaddr_t *addr,
+					int addrlen )
+{
+    return -1;
+}
+#endif	/* PJ_HAS_TCP */
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/efe25a0ba7e95c61b726770ed52f88f6fe0414f1.svn-base b/jni/pjproject-android/.svn/pristine/ef/efe25a0ba7e95c61b726770ed52f88f6fe0414f1.svn-base
new file mode 100644
index 0000000..13a6992
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/efe25a0ba7e95c61b726770ed52f88f6fe0414f1.svn-base
@@ -0,0 +1,36 @@
+/* $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 
+ */
+#ifndef __PJ_COMPAT_M_POWERPC_H__
+#define __PJ_COMPAT_M_POWERPC_H__
+
+/**
+ * @file m_ppc.h
+ * @brief Describes PowerPC family processor specifics.
+ */
+
+#define PJ_M_NAME		"powerpc"
+
+#define PJ_HAS_PENTIUM		0
+#define PJ_IS_LITTLE_ENDIAN	0
+#define PJ_IS_BIG_ENDIAN	1
+
+
+#endif	/* __PJ_COMPAT_M_POWERPC_H__ */
+
diff --git a/jni/pjproject-android/.svn/pristine/ef/eff780736ae7b1a538b416bf7c13798b596d09f3.svn-base b/jni/pjproject-android/.svn/pristine/ef/eff780736ae7b1a538b416bf7c13798b596d09f3.svn-base
new file mode 100644
index 0000000..e477a77
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ef/eff780736ae7b1a538b416bf7c13798b596d09f3.svn-base
@@ -0,0 +1,519 @@
+/*
+ * rtpw.c
+ *
+ * rtp word sender/receiver
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ *
+ * This app is a simple RTP application intended only for testing
+ * libsrtp.  It reads one word at a time from /usr/dict/words (or
+ * whatever file is specified as DICT_FILE), and sends one word out
+ * each USEC_RATE microseconds.  Secure RTP protections can be
+ * applied.  See the usage() function for more details.
+ *
+ */
+
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "datatypes.h"
+#include "getopt_s.h"       /* for local getopt()  */
+
+#include <stdio.h>          /* for printf, fprintf */
+#include <stdlib.h>         /* for atoi()          */
+#include <errno.h>
+#include <unistd.h>         /* for close()         */
+
+#include <string.h>         /* for strncpy()       */
+#include <time.h>	    /* for usleep()        */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#elif defined HAVE_WINSOCK2_H
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define RTPW_USE_WINSOCK2	1
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#include "srtp.h"           
+#include "rtp.h"
+
+#ifdef RTPW_USE_WINSOCK2
+# define DICT_FILE        "words.txt"
+#else
+# define DICT_FILE        "/usr/share/dict/words"
+#endif
+#define USEC_RATE        (5e5)
+#define MAX_WORD_LEN     128  
+#define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a))
+#define MAX_KEY_LEN      64
+#define MASTER_KEY_LEN   30
+
+
+#ifndef HAVE_USLEEP
+# ifdef HAVE_WINDOWS_H
+#  define usleep(us)	Sleep((us)/1000)
+# else
+#  define usleep(us)	sleep((us)/1000000)
+# endif
+#endif
+
+
+/*
+ * the function usage() prints an error message describing how this
+ * program should be called, then calls exit()
+ */
+
+void
+usage(char *prog_name);
+
+/*
+ * leave_group(...) de-registers from a multicast group
+ */
+
+void
+leave_group(int sock, struct ip_mreq mreq, char *name);
+
+
+/*
+ * program_type distinguishes the [s]rtp sender and receiver cases
+ */
+
+typedef enum { sender, receiver, unknown } program_type;
+
+int
+main (int argc, char *argv[]) {
+  char *dictfile = DICT_FILE;
+  FILE *dict;
+  char word[MAX_WORD_LEN];
+  int sock, ret;
+  struct in_addr rcvr_addr;
+  struct sockaddr_in name;
+  struct ip_mreq mreq;
+#if BEW
+  struct sockaddr_in local;
+#endif 
+  program_type prog_type = unknown;
+  sec_serv_t sec_servs = sec_serv_none;
+  unsigned char ttl = 5;
+  int c;
+  char *input_key = NULL;
+  char *address = NULL;
+  char key[MAX_KEY_LEN];
+  unsigned short port = 0;
+  rtp_sender_t snd;
+  srtp_policy_t policy;
+  err_status_t status;
+  int len;
+  int do_list_mods = 0;
+  uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */
+#ifdef RTPW_USE_WINSOCK2
+  WORD wVersionRequested = MAKEWORD(2, 0);
+  WSADATA wsaData;
+
+  ret = WSAStartup(wVersionRequested, &wsaData);
+  if (ret != 0) {
+    fprintf(stderr, "error: WSAStartup() failed: %d\n", ret);
+    exit(1);
+  }
+#endif
+
+  /* initialize srtp library */
+  status = srtp_init();
+  if (status) {
+    printf("error: srtp initialization failed with error code %d\n", status);
+    exit(1);
+  }
+
+  /* check args */
+  while (1) {
+    c = getopt_s(argc, argv, "k:rsaeld:");
+    if (c == -1) {
+      break;
+    }
+    switch (c) {
+    case 'k':
+      input_key = optarg_s;
+      break;
+    case 'e':
+      sec_servs |= sec_serv_conf;
+      break;
+    case 'a':
+      sec_servs |= sec_serv_auth;
+      break;
+    case 'r':
+      prog_type = receiver;
+      break;
+    case 's':
+      prog_type = sender;
+      break;
+    case 'd':
+      status = crypto_kernel_set_debug_module(optarg_s, 1);
+      if (status) {
+        printf("error: set debug module (%s) failed\n", optarg_s);
+        exit(1);
+      }
+      break;
+    case 'l':
+      do_list_mods = 1;
+      break;
+    default:
+      usage(argv[0]);
+    }
+  }
+
+  if (prog_type == unknown) {
+    if (do_list_mods) {
+      status = crypto_kernel_list_debug_modules();
+      if (status) {
+	printf("error: list of debug modules failed\n");
+	exit(1);
+      }
+      return 0;
+    } else {
+      printf("error: neither sender [-s] nor receiver [-r] specified\n");
+      usage(argv[0]);
+    }
+  }
+   
+  if ((sec_servs && !input_key) || (!sec_servs && input_key)) {
+    /* 
+     * a key must be provided if and only if security services have
+     * been requested 
+     */
+    usage(argv[0]);
+  }
+    
+  if (argc != optind_s + 2) {
+    /* wrong number of arguments */
+    usage(argv[0]);
+  }
+
+  /* get address from arg */
+  address = argv[optind_s++];
+
+  /* get port from arg */
+  port = atoi(argv[optind_s++]);
+
+  /* set address */
+#ifdef HAVE_INET_ATON
+  if (0 == inet_aton(address, &rcvr_addr)) {
+    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
+    exit(1);
+  }
+  if (rcvr_addr.s_addr == INADDR_NONE) {
+    fprintf(stderr, "%s: address error", argv[0]);
+    exit(1);
+  }
+#else
+  rcvr_addr.s_addr = inet_addr(address);
+  if (0xffffffff == rcvr_addr.s_addr) {
+    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
+    exit(1);
+  }
+#endif
+
+  /* open socket */
+  sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  if (sock < 0) {
+    int err;
+#ifdef RTPW_USE_WINSOCK2
+    err = WSAGetLastError();
+#else
+    err = errno;
+#endif
+    fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err);
+    exit(1);
+  }
+
+  name.sin_addr   = rcvr_addr;    
+  name.sin_family = PF_INET;
+  name.sin_port   = htons(port);
+ 
+  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    if (prog_type == sender) {
+      ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 
+  	               sizeof(ttl));
+      if (ret < 0) {
+	fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]);
+	perror("");
+	exit(1);
+      }
+    }
+
+    mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr;
+    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+    ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq,
+		     sizeof(mreq));
+    if (ret < 0) {
+      fprintf(stderr, "%s: Failed to join multicast group", argv[0]);
+      perror("");
+      exit(1);
+    }
+  }
+
+  /* report security services selected on the command line */
+  printf("security services: ");
+  if (sec_servs & sec_serv_conf)
+    printf("confidentiality ");
+  if (sec_servs & sec_serv_auth)
+    printf("message authentication");
+  if (sec_servs == sec_serv_none)
+    printf("none");
+  printf("\n");
+  
+  /* set up the srtp policy and master key */    
+  if (sec_servs) {
+    /* 
+     * create policy structure, using the default mechanisms but 
+     * with only the security services requested on the command line,
+     * using the right SSRC value
+     */
+    switch (sec_servs) {
+    case sec_serv_conf_and_auth:
+      crypto_policy_set_rtp_default(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);
+      break;
+    case sec_serv_conf:
+      crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);      
+      break;
+    case sec_serv_auth:
+      crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);
+      break;
+    default:
+      printf("error: unknown security service requested\n");
+      return -1;
+    } 
+    policy.ssrc.type  = ssrc_specific;
+    policy.ssrc.value = ssrc;
+    policy.key  = (uint8_t *) key;
+    policy.next = NULL;
+    policy.rtp.sec_serv = sec_servs;
+    policy.rtcp.sec_serv = sec_serv_none;  /* we don't do RTCP anyway */
+
+    /*
+     * read key from hexadecimal on command line into an octet string
+     */
+    len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2);
+    
+    /* check that hex string is the right length */
+    if (len < MASTER_KEY_LEN*2) {
+      fprintf(stderr, 
+	      "error: too few digits in key/salt "
+	      "(should be %d hexadecimal digits, found %d)\n",
+	      MASTER_KEY_LEN*2, len);
+      exit(1);    
+    } 
+    if (strlen(input_key) > MASTER_KEY_LEN*2) {
+      fprintf(stderr, 
+	      "error: too many digits in key/salt "
+	      "(should be %d hexadecimal digits, found %u)\n",
+	      MASTER_KEY_LEN*2, (unsigned)strlen(input_key));
+      exit(1);    
+    }
+    
+    printf("set master key/salt to %s/", octet_string_hex_string(key, 16));
+    printf("%s\n", octet_string_hex_string(key+16, 14));
+  
+  } else {
+    /*
+     * we're not providing security services, so set the policy to the
+     * null policy
+     *
+     * Note that this policy does not conform to the SRTP
+     * specification, since RTCP authentication is required.  However,
+     * the effect of this policy is to turn off SRTP, so that this
+     * application is now a vanilla-flavored RTP application.
+     */
+    policy.key                 = (uint8_t *)key;
+    policy.ssrc.type           = ssrc_specific;
+    policy.ssrc.value          = ssrc;
+    policy.rtp.cipher_type     = NULL_CIPHER;
+    policy.rtp.cipher_key_len  = 0; 
+    policy.rtp.auth_type       = NULL_AUTH;
+    policy.rtp.auth_key_len    = 0;
+    policy.rtp.auth_tag_len    = 0;
+    policy.rtp.sec_serv        = sec_serv_none;   
+    policy.rtcp.cipher_type    = NULL_CIPHER;
+    policy.rtcp.cipher_key_len = 0; 
+    policy.rtcp.auth_type      = NULL_AUTH;
+    policy.rtcp.auth_key_len   = 0;
+    policy.rtcp.auth_tag_len   = 0;
+    policy.rtcp.sec_serv       = sec_serv_none;   
+    policy.next                = NULL;
+  }
+
+  if (prog_type == sender) {
+
+#if BEW
+    /* bind to local socket (to match crypto policy, if need be) */
+    memset(&local, 0, sizeof(struct sockaddr_in));
+    local.sin_addr.s_addr = htonl(INADDR_ANY);
+    local.sin_port = htons(port);
+    ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in));
+    if (ret < 0) {
+      fprintf(stderr, "%s: bind failed\n", argv[0]);
+      perror("");
+      exit(1); 
+    }
+#endif /* BEW */
+
+    /* initialize sender's rtp and srtp contexts */
+    snd = rtp_sender_alloc();
+    if (snd == NULL) {
+      fprintf(stderr, "error: malloc() failed\n");
+      exit(1);
+    }
+    rtp_sender_init(snd, sock, name, ssrc); 
+    status = rtp_sender_init_srtp(snd, &policy);
+    if (status) {
+      fprintf(stderr, 
+	      "error: srtp_create() failed with code %d\n", 
+	      status);
+      exit(1);
+    }
+ 
+    /* open dictionary */
+    dict = fopen (dictfile, "r");
+    if (dict == NULL) {
+      fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile);
+      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+  	leave_group(sock, mreq, argv[0]);
+      }
+      exit(1);
+    }
+          
+    /* read words from dictionary, then send them off */
+    while (fgets(word, MAX_WORD_LEN, dict) != NULL) { 
+      len = strlen(word) + 1;  /* plus one for null */
+      
+      if (len > MAX_WORD_LEN) 
+	printf("error: word %s too large to send\n", word);
+      else {
+	rtp_sendto(snd, word, len);
+        printf("sending word: %s", word);
+      }
+      usleep(USEC_RATE);
+    }
+    
+  } else  { /* prog_type == receiver */
+    rtp_receiver_t rcvr;
+        
+    if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
+      close(sock);
+      fprintf(stderr, "%s: socket bind error\n", argv[0]);
+      perror(NULL);
+      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    	leave_group(sock, mreq, argv[0]);
+      }
+      exit(1);
+    }
+
+    rcvr = rtp_receiver_alloc();
+    if (rcvr == NULL) {
+      fprintf(stderr, "error: malloc() failed\n");
+      exit(1);
+    }
+    rtp_receiver_init(rcvr, sock, name, ssrc);
+    status = rtp_receiver_init_srtp(rcvr, &policy);
+    if (status) {
+      fprintf(stderr, 
+	      "error: srtp_create() failed with code %d\n", 
+	      status);
+      exit(1);
+    }
+
+    /* get next word and loop */
+    while (1) {
+      len = MAX_WORD_LEN;
+      if (rtp_recvfrom(rcvr, word, &len) > -1)
+	printf("\tword: %s", word);
+    }
+      
+  } 
+
+  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    leave_group(sock, mreq, argv[0]);
+  }
+
+#ifdef RTPW_USE_WINSOCK2
+  WSACleanup();
+#endif
+
+  return 0;
+}
+
+
+void
+usage(char *string) {
+
+  printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] "
+	 "[-s | -r] dest_ip dest_port\n"
+	 "or     %s -l\n"
+	 "where  -a use message authentication\n"
+	 "       -e use encryption\n"
+	 "       -k <key>  sets the srtp master key\n"
+	 "       -s act as rtp sender\n"
+	 "       -r act as rtp receiver\n"
+	 "       -l list debug modules\n"
+	 "       -d <debug> turn on debugging for module <debug>\n",
+	 string, string);
+  exit(1);
+  
+}
+
+
+void
+leave_group(int sock, struct ip_mreq mreq, char *name) {
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*)&mreq,
+		   sizeof(mreq));
+  if (ret < 0) {
+	fprintf(stderr, "%s: Failed to leave multicast group", name);
+	perror("");
+  }
+}
+