* #27232: jni: added pjproject checkout as regular git content

We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/41/4199d381adc74a5a48b881fa9ed24ed30a2aea36.svn-base b/jni/pjproject-android/.svn/pristine/41/4199d381adc74a5a48b881fa9ed24ed30a2aea36.svn-base
new file mode 100644
index 0000000..f1ad9a1
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/41/4199d381adc74a5a48b881fa9ed24ed30a2aea36.svn-base
@@ -0,0 +1,1135 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2012 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 is the implementation of BlackBerry 10 (BB10) audio device.
+ * Original code was kindly donated by Truphone Ltd. (http://www.truphone.com)
+ * The key methods here are bb10_capture_open, bb10_play_open together
+ * with the capture and play threads ca_thread_func and pb_thread_func
+ */
+
+#include <pjmedia_audiodev.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pjmedia/errno.h>
+
+#if defined(PJMEDIA_AUDIO_DEV_HAS_BB10) && PJMEDIA_AUDIO_DEV_HAS_BB10 != 0
+
+#ifndef PJ_BBSDK_VER
+    /* Format: 0xMMNNRR:  MM: major, NN: minor, RR: revision */
+#   define PJ_BBSDK_VER	0x100006
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <pthread.h>
+#include <errno.h>
+#include <sys/asoundlib.h>
+#if PJ_BBSDK_VER >= 0x100006
+#include <audio/audio_manager_routing.h>
+#endif
+
+
+#define THIS_FILE 			"bb10_dev.c"
+#define BB10_DEVICE_NAME 		"plughw:%d,%d"
+
+
+/* Set to 1 to enable tracing */
+#if 1
+#    define TRACE_(expr)		PJ_LOG(4,expr)
+#else
+#    define TRACE_(expr)
+#endif
+
+/*
+ * Factory prototypes
+ */
+static pj_status_t bb10_factory_init(pjmedia_aud_dev_factory *f);
+static pj_status_t bb10_factory_destroy(pjmedia_aud_dev_factory *f);
+static pj_status_t bb10_factory_refresh(pjmedia_aud_dev_factory *f);
+static unsigned    bb10_factory_get_dev_count(pjmedia_aud_dev_factory *f);
+static pj_status_t bb10_factory_get_dev_info(pjmedia_aud_dev_factory *f,
+                                             unsigned index,
+                                             pjmedia_aud_dev_info *info);
+static pj_status_t bb10_factory_default_param(pjmedia_aud_dev_factory *f,
+                                              unsigned index,
+                                              pjmedia_aud_param *param);
+static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
+                                              const pjmedia_aud_param *param,
+                                              pjmedia_aud_rec_cb rec_cb,
+                                              pjmedia_aud_play_cb play_cb,
+                                              void *user_data,
+                                              pjmedia_aud_stream **p_strm);
+
+/*
+ * Stream prototypes
+ */
+static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *strm,
+                                         pjmedia_aud_param *param);
+static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *strm,
+                                       pjmedia_aud_dev_cap cap,
+                                       void *value);
+static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
+                                       pjmedia_aud_dev_cap cap,
+                                       const void *value);
+static pj_status_t bb10_stream_start(pjmedia_aud_stream *strm);
+static pj_status_t bb10_stream_stop(pjmedia_aud_stream *strm);
+static pj_status_t bb10_stream_destroy(pjmedia_aud_stream *strm);
+
+
+struct bb10_factory
+{
+    pjmedia_aud_dev_factory	 base;
+    pj_pool_factory		*pf;
+    pj_pool_t			*pool;
+    pj_pool_t			*base_pool;
+    unsigned			 dev_cnt;
+    pjmedia_aud_dev_info	 devs[1];
+};
+
+struct bb10_stream
+{
+    pjmedia_aud_stream	 base;
+
+    /* Common */
+    pj_pool_t		*pool;
+    struct bb10_factory *af;
+    void		*user_data;
+    pjmedia_aud_param	 param;		/* Running parameter 		*/
+    int                  rec_id;      	/* Capture device id		*/
+    int                  quit;
+
+    /* Playback */
+    unsigned int pb_ctrl_audio_manager_handle;
+    snd_pcm_t		*pb_pcm;
+    unsigned int pb_audio_manager_handle;
+    unsigned long        pb_frames; 	/* samples_per_frame		*/
+    pjmedia_aud_play_cb  pb_cb;
+    unsigned             pb_buf_size;
+    char		*pb_buf;
+    pj_thread_t		*pb_thread;
+
+    /* Capture */
+    snd_pcm_t		*ca_pcm;
+    unsigned int ca_audio_manager_handle;
+    unsigned long        ca_frames; 	/* samples_per_frame		*/
+    pjmedia_aud_rec_cb   ca_cb;
+    unsigned             ca_buf_size;
+    char		*ca_buf;
+    pj_thread_t		*ca_thread;
+};
+
+static pjmedia_aud_dev_factory_op bb10_factory_op =
+{
+    &bb10_factory_init,
+    &bb10_factory_destroy,
+    &bb10_factory_get_dev_count,
+    &bb10_factory_get_dev_info,
+    &bb10_factory_default_param,
+    &bb10_factory_create_stream,
+    &bb10_factory_refresh
+};
+
+static pjmedia_aud_stream_op bb10_stream_op =
+{
+    &bb10_stream_get_param,
+    &bb10_stream_get_cap,
+    &bb10_stream_set_cap,
+    &bb10_stream_start,
+    &bb10_stream_stop,
+    &bb10_stream_destroy
+};
+
+/*
+ * BB10 - tests loads the audio units and sets up the driver structure
+ */
+static pj_status_t bb10_add_dev (struct bb10_factory *af)
+{
+    pjmedia_aud_dev_info *adi;
+    int pb_result, ca_result;
+    unsigned int handle;
+    snd_pcm_t *pcm_handle;
+
+    if (af->dev_cnt >= PJ_ARRAY_SIZE(af->devs))
+        return PJ_ETOOMANY;
+
+    adi = &af->devs[af->dev_cnt];
+
+    TRACE_((THIS_FILE, "bb10_add_dev Enter"));
+
+    if ((pb_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
+                                                     &pcm_handle,
+                                                     &handle,
+                                                     (char*)"voice",
+                                                     SND_PCM_OPEN_PLAYBACK))
+                                                     >= 0)
+    {
+	snd_pcm_close (pcm_handle);
+	audio_manager_free_handle(handle);
+    } else {
+        TRACE_((THIS_FILE, "Try to open the device for playback - failure"));
+    }
+
+    if ((ca_result = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
+                                                     &pcm_handle,
+                                                     &handle,
+                                                     (char*)"voice",
+                                                     SND_PCM_OPEN_CAPTURE))
+                                                     >= 0)
+    {
+	snd_pcm_close (pcm_handle);
+	audio_manager_free_handle(handle);
+
+    } else {
+        TRACE_((THIS_FILE, "Try to open the device for capture - failure"));
+    }
+
+    if (pb_result < 0 && ca_result < 0) {
+        TRACE_((THIS_FILE, "Unable to open sound device", "preferred"));
+        return PJMEDIA_EAUD_NODEV;
+    }
+
+    /* Reset device info */
+    pj_bzero(adi, sizeof(*adi));
+
+    /* Set device name */
+    strcpy(adi->name, "preferred");
+
+    /* Check the number of playback channels */
+    adi->output_count = (pb_result >= 0) ? 1 : 0;
+
+    /* Check the number of capture channels */
+    adi->input_count = (ca_result >= 0) ? 1 : 0;
+
+    /* Set the default sample rate */
+    adi->default_samples_per_sec = 8000;
+
+    /* Driver name */
+    strcpy(adi->driver, "BB10");
+
+    ++af->dev_cnt;
+
+    PJ_LOG (4,(THIS_FILE, "Added sound device %s", adi->name));
+
+    return PJ_SUCCESS;
+}
+
+/* Create BB10 audio driver. */
+pjmedia_aud_dev_factory* pjmedia_bb10_factory(pj_pool_factory *pf)
+{
+    struct bb10_factory *af;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "bb10_aud_base", 256, 256, NULL);
+    af = PJ_POOL_ZALLOC_T(pool, struct bb10_factory);
+    af->pf = pf;
+    af->base_pool = pool;
+    af->base.op = &bb10_factory_op;
+
+    return &af->base;
+}
+
+
+/* API: init factory */
+static pj_status_t bb10_factory_init(pjmedia_aud_dev_factory *f)
+{
+    pj_status_t status;
+
+    status = bb10_factory_refresh(f);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    PJ_LOG(4,(THIS_FILE, "BB10 initialized"));
+    return PJ_SUCCESS;
+}
+
+
+/* API: destroy factory */
+static pj_status_t bb10_factory_destroy(pjmedia_aud_dev_factory *f)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+
+    if (af->pool) {
+        TRACE_((THIS_FILE, "bb10_factory_destroy() - 1"));
+        pj_pool_release(af->pool);
+    }
+
+    if (af->base_pool) {
+        pj_pool_t *pool = af->base_pool;
+        af->base_pool = NULL;
+        TRACE_((THIS_FILE, "bb10_factory_destroy() - 2"));
+        pj_pool_release(pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: refresh the device list */
+static pj_status_t bb10_factory_refresh(pjmedia_aud_dev_factory *f)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+    int err;
+
+    TRACE_((THIS_FILE, "bb10_factory_refresh()"));
+
+    if (af->pool != NULL) {
+        pj_pool_release(af->pool);
+        af->pool = NULL;
+    }
+
+    af->pool = pj_pool_create(af->pf, "bb10_aud", 256, 256, NULL);
+    af->dev_cnt = 0;
+
+    err = bb10_add_dev(af);
+
+    PJ_LOG(4,(THIS_FILE, "BB10 driver found %d devices", af->dev_cnt));
+
+    return err;
+}
+
+
+/* API: get device count */
+static unsigned  bb10_factory_get_dev_count(pjmedia_aud_dev_factory *f)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+    return af->dev_cnt;
+}
+
+
+/* API: get device info */
+static pj_status_t bb10_factory_get_dev_info(pjmedia_aud_dev_factory *f,
+                                             unsigned index,
+                                             pjmedia_aud_dev_info *info)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+
+    PJ_ASSERT_RETURN(index>=0 && index<af->dev_cnt, PJ_EINVAL);
+
+    pj_memcpy(info, &af->devs[index], sizeof(*info));
+    info->caps = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
+                 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
+                 PJMEDIA_AUD_DEV_CAP_EC;
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default parameter */
+static pj_status_t bb10_factory_default_param(pjmedia_aud_dev_factory *f,
+                                              unsigned index,
+                                              pjmedia_aud_param *param)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+    pjmedia_aud_dev_info *adi;
+
+    PJ_ASSERT_RETURN(index>=0 && index<af->dev_cnt, PJ_EINVAL);
+
+    adi = &af->devs[index];
+
+    pj_bzero(param, sizeof(*param));
+    if (adi->input_count && adi->output_count) {
+        param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+        param->rec_id = index;
+        param->play_id = index;
+    } else if (adi->input_count) {
+        param->dir = PJMEDIA_DIR_CAPTURE;
+        param->rec_id = index;
+        param->play_id = PJMEDIA_AUD_INVALID_DEV;
+    } else if (adi->output_count) {
+        param->dir = PJMEDIA_DIR_PLAYBACK;
+        param->play_id = index;
+        param->rec_id = PJMEDIA_AUD_INVALID_DEV;
+    } else {
+        return PJMEDIA_EAUD_INVDEV;
+    }
+
+    param->clock_rate = adi->default_samples_per_sec;
+    param->channel_count = 1;
+    param->samples_per_frame = adi->default_samples_per_sec * 20 / 1000;
+    param->bits_per_sample = 16;
+    param->flags = adi->caps;
+    param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
+    param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
+
+    TRACE_((THIS_FILE, "bb10_factory_default_param clock = %d flags = %d"
+                       " spf = %d", param->clock_rate, param->flags,
+                       param->samples_per_frame));
+
+    return PJ_SUCCESS;
+}
+
+
+static void close_play_pcm(struct bb10_stream *stream)
+{
+    if (stream != NULL && stream->pb_pcm != NULL) {
+        snd_pcm_close(stream->pb_pcm);
+        stream->pb_pcm = NULL;
+
+        if (stream->pb_audio_manager_handle != 0) {
+    	    audio_manager_free_handle(stream->pb_audio_manager_handle);
+    	    stream->pb_audio_manager_handle = 0;
+        }
+
+        if (stream->pb_ctrl_audio_manager_handle != 0) {
+    	    audio_manager_free_handle(stream->pb_ctrl_audio_manager_handle);
+    	    stream->pb_ctrl_audio_manager_handle = 0;
+        }
+    }
+}
+
+static void flush_play(struct bb10_stream *stream)
+{
+    if (stream != NULL && stream->pb_pcm != NULL) {
+        snd_pcm_plugin_flush (stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK);
+    }
+}
+
+static void close_capture_pcm(struct bb10_stream *stream)
+{
+    if (stream != NULL && stream->ca_pcm != NULL) {
+        snd_pcm_close(stream->ca_pcm);
+        stream->ca_pcm = NULL;
+
+        if (stream->ca_audio_manager_handle != 0) {
+    	    audio_manager_free_handle(stream->ca_audio_manager_handle);
+    	    stream->ca_audio_manager_handle = 0;
+        }
+    }
+}
+
+static void flush_capture(struct bb10_stream *stream)
+{
+    if (stream != NULL && stream->ca_pcm != NULL) {
+        snd_pcm_plugin_flush (stream->ca_pcm, SND_PCM_CHANNEL_CAPTURE);
+    }
+}
+
+
+/**
+ * Play audio received from PJMEDIA
+ */
+static int pb_thread_func (void *arg)
+{
+    struct bb10_stream* stream = (struct bb10_stream *) arg;
+    int size                   	= stream->pb_buf_size;
+    unsigned long nframes	= stream->pb_frames;
+    void *user_data            	= stream->user_data;
+    char *buf 		       	= stream->pb_buf;
+    pj_timestamp tstamp;
+    int result = 0;
+    int policy;
+    struct sched_param param;
+
+    TRACE_((THIS_FILE, "pb_thread_func: size = %d ", size));
+
+    if (pthread_getschedparam(pthread_self(), &policy, &param) == 0) {
+	param.sched_priority = 18;
+	pthread_setschedparam (pthread_self(), policy, &param);
+    }
+
+    pj_bzero (buf, size);
+    tstamp.u64 = 0;
+
+    /* Do the final initialization now the thread has started. */
+    if ((result = snd_pcm_plugin_prepare(stream->pb_pcm,
+                                         SND_PCM_CHANNEL_PLAYBACK)) < 0)
+    {
+        close_play_pcm(stream);
+        TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result));
+        return PJ_SUCCESS;
+    }
+
+    while (!stream->quit) {
+        pjmedia_frame frame;
+
+        frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+        /* pointer to buffer filled by PJMEDIA */
+        frame.buf = buf;
+        frame.size = size;
+        frame.timestamp.u64 = tstamp.u64;
+        frame.bit_info = 0;
+
+        /* Read the audio from pjmedia */
+        result = stream->pb_cb (user_data, &frame);
+        if (result != PJ_SUCCESS || stream->quit)
+            break;
+
+        if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+            pj_bzero (buf, size);
+
+        /* Write 640 to play unit */
+        result = snd_pcm_plugin_write(stream->pb_pcm,buf,size);
+        if (result != size || result < 0) {
+	    /* either the write to output device has failed or not the
+	     * full amount of bytes have been written. This usually happens
+	     * when audio routing is being changed by another thread
+	     * Use a status variable for reading the error
+	     */
+	    snd_pcm_channel_status_t status;
+            status.channel = SND_PCM_CHANNEL_PLAYBACK;
+            if (snd_pcm_plugin_status (stream->pb_pcm, &status) < 0) {
+                /* Call has failed nothing we can do except log and
+                 * continue */
+            	PJ_LOG(4,(THIS_FILE,
+                	  "underrun: playback channel status error"));
+            } else {
+            	/* The status of the error has been read
+            	 * RIM say these are expected so we can "re-prepare" the stream
+            	 */
+            	PJ_LOG(4,(THIS_FILE,"PLAY thread ERROR status = %d",
+            		  status.status));
+		if (status.status == SND_PCM_STATUS_READY ||
+		    status.status == SND_PCM_STATUS_UNDERRUN ||
+		    status.status == SND_PCM_STATUS_ERROR ) 
+		{
+		    if (snd_pcm_plugin_prepare (stream->pb_pcm,
+						SND_PCM_CHANNEL_PLAYBACK) < 0)
+		    {
+			PJ_LOG(4,(THIS_FILE,
+				  "underrun: playback channel prepare error"));
+		    }
+		}
+	    }
+        }
+	tstamp.u64 += nframes;
+    }
+
+    flush_play(stream);
+    close_play_pcm(stream);
+    TRACE_((THIS_FILE, "pb_thread_func: Stopped"));
+
+    return PJ_SUCCESS;
+}
+
+
+
+static int ca_thread_func (void *arg)
+{
+    struct bb10_stream* stream = (struct bb10_stream *) arg;
+    int size                   = stream->ca_buf_size;
+    unsigned long nframes      = stream->ca_frames;
+    void *user_data            = stream->user_data;
+    /* Buffer to fill for PJMEDIA */
+    char *buf 		       = stream->ca_buf;
+    pj_timestamp tstamp;
+    int result;
+    int policy;
+    struct sched_param param;
+
+    TRACE_((THIS_FILE, "ca_thread_func: size = %d ", size));
+
+    if (pthread_getschedparam(pthread_self(), &policy, &param) == 0) {
+	param.sched_priority = 18;
+	pthread_setschedparam (pthread_self(), policy, &param);
+    }
+
+    pj_bzero (buf, size);
+    tstamp.u64 = 0;
+
+    /* Final init now the thread has started */
+    if ((result = snd_pcm_plugin_prepare (stream->ca_pcm,
+                                          SND_PCM_CHANNEL_CAPTURE)) < 0)
+    {
+        close_capture_pcm(stream);
+        TRACE_((THIS_FILE, "ca_thread_func failed prepare = %d", result));
+        return PJ_SUCCESS;
+    }
+
+    while (!stream->quit) {
+        pjmedia_frame frame;
+
+        //pj_bzero (buf, size);
+
+        /* read the input device */
+        result = snd_pcm_plugin_read(stream->ca_pcm, buf,size);
+        if(result <0 || result != size) {
+            /* We expect result to be size (640)
+             * It's not so we have to read the status error and "prepare"
+             * the channel. This usually happens when output audio routing
+             * has been changed by another thread.
+             * We won't "continue", instead just do what we can and leave
+             * the end of the loop to write what's in the buffer. Not entirely
+             * correct but saves a potential underrun in PJMEDIA
+             */
+            PJ_LOG (4,(THIS_FILE,
+        	       "snd_pcm_plugin_read ERROR read = %d required = %d",
+        	       result,size));
+            snd_pcm_channel_status_t status;
+            status.channel = SND_PCM_CHANNEL_CAPTURE;
+            if ((result = snd_pcm_plugin_status (stream->ca_pcm, &status)) < 0)
+            {
+        	/* Should not fail but all we can do is continue */
+        	PJ_LOG(4,(THIS_FILE, "capture: snd_pcm_plugin_status ret = %d",
+        		  result));
+            } else {
+        	/* RIM say these are the errors that we should "prepare"
+        	 * after */
+        	if (status.status == SND_PCM_STATUS_READY ||
+        		status.status == SND_PCM_STATUS_OVERRUN ||
+        		status.status == SND_PCM_STATUS_ERROR)
+        	{
+        	    if (snd_pcm_plugin_prepare (stream->ca_pcm,
+        	                                SND_PCM_CHANNEL_CAPTURE) < 0)
+        	    {
+        		PJ_LOG (4,(THIS_FILE,
+        			   "overrun: capture channel prepare  error"));
+        	    }
+        	}
+            }
+        }
+
+        if (stream->quit)
+            break;
+
+        /* Write the capture audio data to PJMEDIA */
+        frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+        frame.buf = (void *) buf;
+        frame.size = size;
+        frame.timestamp.u64 = tstamp.u64;
+        frame.bit_info = 0;
+
+        result = stream->ca_cb (user_data, &frame);
+        if (result != PJ_SUCCESS || stream->quit)
+            break;
+
+        tstamp.u64 += nframes;
+    }
+
+    flush_capture(stream);
+    close_capture_pcm(stream);
+    TRACE_((THIS_FILE, "ca_thread_func: Stopped"));
+
+    return PJ_SUCCESS;
+}
+
+/* Audio routing, speaker/headset */
+static pj_status_t bb10_initialize_playback_ctrl(struct bb10_stream *stream,
+                                                 bool speaker)
+{
+    /* Although the play and capture have audio manager handles, audio routing
+     * requires a separate handle
+     */
+    int ret = PJ_SUCCESS;
+
+    if (stream->pb_ctrl_audio_manager_handle == 0) {
+	/* lazy init an audio manager handle */
+	ret = audio_manager_get_handle(AUDIO_TYPE_VOICE, 0, false,
+	                               &stream->pb_ctrl_audio_manager_handle);
+	if (ret != 0) {
+	    TRACE_((THIS_FILE, "audio_manager_get_handle ret = %d",ret));
+	    return PJMEDIA_EAUD_SYSERR;
+	}
+    }
+
+    /* Set for either speaker or earpiece */
+    if (speaker) {
+	ret = audio_manager_set_handle_type(
+		stream->pb_ctrl_audio_manager_handle,
+		AUDIO_TYPE_VIDEO_CHAT,
+		AUDIO_DEVICE_DEFAULT,
+		AUDIO_DEVICE_DEFAULT);
+    } else {
+	ret = audio_manager_set_handle_type(
+		stream->pb_ctrl_audio_manager_handle,
+		AUDIO_TYPE_VOICE,
+		AUDIO_DEVICE_DEFAULT,
+		AUDIO_DEVICE_DEFAULT);
+    }
+
+    if (ret != 0) {
+        return PJMEDIA_EAUD_SYSERR;
+    }else{
+        return PJ_SUCCESS;
+    }
+}
+
+static int32_t get_alsa_pcm_fmt(const pjmedia_aud_param *param)
+{
+    switch (param->bits_per_sample) {
+    case 8:
+	return SND_PCM_SFMT_S8;
+    case 16:
+	return SND_PCM_SFMT_S16_LE;
+    case 24:
+	return SND_PCM_SFMT_S24_LE;
+    case 32:
+	return SND_PCM_SFMT_S32_LE;
+    default:
+	PJ_ASSERT_RETURN(!"Unsupported bits_per_frame", SND_PCM_SFMT_S16_LE);
+    }
+}
+
+static pj_status_t bb10_open_playback (struct bb10_stream *stream,
+                                       const pjmedia_aud_param *param)
+{
+    int ret = 0;
+    snd_pcm_channel_info_t pi;
+    snd_pcm_channel_setup_t setup;
+    snd_mixer_group_t group;
+    snd_pcm_channel_params_t pp;
+    unsigned int rate;
+    unsigned long tmp_buf_size;
+
+    if (param->play_id < 0 || param->play_id >= stream->af->dev_cnt) {
+        return PJMEDIA_EAUD_INVDEV;
+    }
+
+    PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT);
+
+    /* Use the bb10 audio manager API to open as opposed to QNX core audio
+     * Echo cancellation built in
+     */
+    if ((ret = audio_manager_snd_pcm_open_name(
+	    AUDIO_TYPE_VIDEO_CHAT,
+            &stream->pb_pcm, &stream->pb_audio_manager_handle,
+            (char*)"voice",
+            SND_PCM_OPEN_PLAYBACK)) < 0)
+    {
+        TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    /* Required call from January 2013 gold OS release */
+    snd_pcm_plugin_set_disable(stream->pb_pcm, PLUGIN_DISABLE_MMAP);
+
+    /* Required call from January 2013 gold OS release */
+    snd_pcm_plugin_set_enable(stream->pb_pcm, PLUGIN_ROUTING);
+
+    memset (&pi, 0, sizeof (pi));
+    pi.channel = SND_PCM_CHANNEL_PLAYBACK;
+    if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) {
+	TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
+	return PJMEDIA_EAUD_SYSERR;
+    }
+
+    memset (&pp, 0, sizeof (pp));
+
+    /* Request VoIP compatible capabilities */
+    pp.mode = SND_PCM_MODE_BLOCK;
+    pp.channel = SND_PCM_CHANNEL_PLAYBACK;
+    pp.start_mode = SND_PCM_START_FULL;
+    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
+    pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8;
+    /* RIM recommends maximum of 5 */
+    pp.buf.block.frags_max = 5;
+    pp.buf.block.frags_min = 1;
+    pp.format.interleave = 1;
+    pp.format.rate = param->clock_rate;
+    pp.format.voices = param->channel_count;
+    pp.format.format = get_alsa_pcm_fmt(param);
+
+    /* Make the calls as per the wave sample */
+    if ((ret = snd_pcm_plugin_params (stream->pb_pcm, &pp)) < 0) {
+        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    memset (&setup, 0, sizeof (setup));
+    memset (&group, 0, sizeof (group));
+    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
+    setup.mixer_gid = &group.gid;
+
+    if ((ret = snd_pcm_plugin_setup (stream->pb_pcm, &setup)) < 0) {
+        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    if (group.gid.name[0] == 0) {
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    rate = param->clock_rate;
+    /* Set the sound device buffer size and latency */
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
+        tmp_buf_size = rate * param->output_latency_ms / 1000;
+    } else {
+	tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_PLAY_LATENCY / 1000;
+    }
+    /* Set period size to samples_per_frame frames. */
+    stream->pb_frames = param->samples_per_frame / param->channel_count;
+    stream->param.output_latency_ms = tmp_buf_size * 1000 / rate;
+
+    /* Set our buffer */
+    stream->pb_buf_size = stream->pb_frames * param->channel_count *
+                          param->bits_per_sample / 8;
+    stream->pb_buf = (char *) pj_pool_alloc(stream->pool, stream->pb_buf_size);
+
+    TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d",
+                       stream->pb_frames, param->clock_rate));
+    
+    return PJ_SUCCESS;
+}
+
+static pj_status_t bb10_open_capture (struct bb10_stream *stream,
+                                      const pjmedia_aud_param *param)
+{
+    int ret = 0;
+    unsigned int rate;
+    unsigned long tmp_buf_size;
+    int frame_size;
+    snd_pcm_channel_info_t pi;
+    snd_mixer_group_t group;
+    snd_pcm_channel_params_t pp;
+    snd_pcm_channel_setup_t setup;
+
+    if (param->rec_id < 0 || param->rec_id >= stream->af->dev_cnt)
+        return PJMEDIA_EAUD_INVDEV;
+
+    PJ_ASSERT_RETURN(param->bits_per_sample == 16, PJMEDIA_EAUD_SAMPFORMAT);
+
+    if ((ret=audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,
+                                             &stream->ca_pcm,
+                                             &stream->ca_audio_manager_handle,
+                                             (char*)"voice",
+                                             SND_PCM_OPEN_CAPTURE)) < 0)
+    {
+	TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret));
+	return PJMEDIA_EAUD_SYSERR;
+    }
+    /* Required call from January 2013 gold OS release */
+    snd_pcm_plugin_set_disable (stream->ca_pcm, PLUGIN_DISABLE_MMAP);
+
+    /* Required call from January 2013 gold OS release */
+    snd_pcm_plugin_set_enable(stream->ca_pcm, PLUGIN_ROUTING);
+
+    /* sample reads the capabilities of the capture */
+    memset (&pi, 0, sizeof (pi));
+    pi.channel = SND_PCM_CHANNEL_CAPTURE;
+    if ((ret = snd_pcm_plugin_info (stream->ca_pcm, &pi)) < 0) {
+        TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    /* Request the VoIP parameters
+     * These parameters are different to waverec sample
+     */
+    memset (&pp, 0, sizeof (pp));
+    /* Blocking read */
+    pp.mode = SND_PCM_MODE_BLOCK;
+    pp.channel = SND_PCM_CHANNEL_CAPTURE;
+    pp.start_mode = SND_PCM_START_FULL;
+    /* Auto-recover from errors */
+    pp.stop_mode = SND_PCM_STOP_ROLLOVER;
+    pp.buf.block.frag_size = param->samples_per_frame * param->bits_per_sample / 8;
+    /* From January 2013 gold OS release. RIM recommend these for capture */
+    pp.buf.block.frags_max = 3;
+    pp.buf.block.frags_min = 1;
+    pp.format.interleave = 1;
+    pp.format.rate = param->clock_rate;
+    pp.format.voices = param->channel_count;
+    pp.format.format = get_alsa_pcm_fmt(param);
+
+    /* make the request */
+    if ((ret = snd_pcm_plugin_params (stream->ca_pcm, &pp)) < 0) {
+        TRACE_((THIS_FILE, "snd_pcm_plugin_params ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    /* Again based on the sample */
+    memset (&setup, 0, sizeof (setup));
+    memset (&group, 0, sizeof (group));
+    setup.channel = SND_PCM_CHANNEL_CAPTURE;
+    setup.mixer_gid = &group.gid;
+    if ((ret = snd_pcm_plugin_setup (stream->ca_pcm, &setup)) < 0) {
+        TRACE_((THIS_FILE, "snd_pcm_plugin_setup ret = %d", ret));
+        return PJMEDIA_EAUD_SYSERR;
+    }
+
+    frame_size = setup.buf.block.frag_size;
+
+    if (group.gid.name[0] == 0) {
+    } else {
+    }
+
+    frame_size = setup.buf.block.frag_size;
+
+    /* Set clock rate */
+    rate = param->clock_rate;
+    stream->ca_frames = (unsigned long) param->samples_per_frame /
+			param->channel_count;
+
+    /* Set the sound device buffer size and latency */
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
+        tmp_buf_size = rate * param->input_latency_ms / 1000;
+    } else {
+        tmp_buf_size = rate * PJMEDIA_SND_DEFAULT_REC_LATENCY / 1000;
+    }
+
+    stream->param.input_latency_ms = tmp_buf_size * 1000 / rate;
+
+    /* Set our buffer */
+    stream->ca_buf_size = stream->ca_frames * param->channel_count *
+			  param->bits_per_sample / 8;
+    stream->ca_buf = (char *)pj_pool_alloc (stream->pool, stream->ca_buf_size);
+
+    TRACE_((THIS_FILE, "bb10_open_capture: ca_frames = %d clock = %d",
+                       stream->ca_frames, param->clock_rate));
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: create stream */
+static pj_status_t bb10_factory_create_stream(pjmedia_aud_dev_factory *f,
+                                              const pjmedia_aud_param *param,
+                                              pjmedia_aud_rec_cb rec_cb,
+                                              pjmedia_aud_play_cb play_cb,
+                                              void *user_data,
+                                              pjmedia_aud_stream **p_strm)
+{
+    struct bb10_factory *af = (struct bb10_factory*)f;
+    pj_status_t status;
+    pj_pool_t* pool;
+    struct bb10_stream* stream;
+
+    pool = pj_pool_create (af->pf, "bb10%p", 1024, 1024, NULL);
+    if (!pool)
+        return PJ_ENOMEM;
+
+    /* Allocate and initialize comon stream data */
+    stream = PJ_POOL_ZALLOC_T (pool, struct bb10_stream);
+    stream->base.op   = &bb10_stream_op;
+    stream->pool      = pool;
+    stream->af 	      = af;
+    stream->user_data = user_data;
+    stream->pb_cb     = play_cb;
+    stream->ca_cb     = rec_cb;
+    stream->quit      = 0;
+    pj_memcpy(&stream->param, param, sizeof(*param));
+
+    /* Init playback */
+    if (param->dir & PJMEDIA_DIR_PLAYBACK) {
+        status = bb10_open_playback (stream, param);
+        if (status != PJ_SUCCESS) {
+            pj_pool_release (pool);
+            return status;
+        }
+    }
+
+    /* Init capture */
+    if (param->dir & PJMEDIA_DIR_CAPTURE) {
+        status = bb10_open_capture (stream, param);
+        if (status != PJ_SUCCESS) {
+            if (param->dir & PJMEDIA_DIR_PLAYBACK) {
+                close_play_pcm(stream);
+            }
+            pj_pool_release (pool);
+            return status;
+        }
+    }
+
+    /* Set the audio routing ONLY if app explicitly asks one */
+    if ((param->dir & PJMEDIA_DIR_PLAYBACK) &&
+	(param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE))
+    {
+	status = bb10_stream_set_cap(&stream->base,
+				     PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+                                     &param->output_route);
+	if (status != PJ_SUCCESS) {
+	    TRACE_((THIS_FILE, "Error setting output route"));
+	    bb10_stream_destroy(&stream->base);
+	    return status;
+	}
+    } else {
+	/* Legacy behavior: if none specified, set to speaker */
+	status = bb10_initialize_playback_ctrl(stream, false);
+    }
+
+    *p_strm = &stream->base;
+    return PJ_SUCCESS;
+}
+
+
+/* 
+ * API: get running parameter
+ * based on ALSA template
+ */
+static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *s,
+                                         pjmedia_aud_param *pi)
+{
+    struct bb10_stream *stream = (struct bb10_stream*)s;
+
+    PJ_ASSERT_RETURN(s && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &stream->param, sizeof(*pi));
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * API: get capability
+ * based on ALSA template 
+*/
+static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *s,
+                                       pjmedia_aud_dev_cap cap,
+                                       void *pval)
+{
+    struct bb10_stream *stream = (struct bb10_stream*)s;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY &&
+        (stream->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+        /* Recording latency */
+        *(unsigned*)pval = stream->param.input_latency_ms;
+        return PJ_SUCCESS;
+
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY &&
+               (stream->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+        /* Playback latency */
+        *(unsigned*)pval = stream->param.output_latency_ms;
+        return PJ_SUCCESS;
+
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_EC &&
+	       (stream->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+	/* EC is enablied implicitly by opening "voice" device */
+	*(pj_bool_t*)pval = PJ_TRUE;
+	return PJ_SUCCESS;
+    } else {
+        return PJMEDIA_EAUD_INVCAP;
+    }
+}
+
+
+/*
+ * API: set capability
+ * Currently just supporting toggle between speaker and earpiece
+ */
+static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm,
+                                       pjmedia_aud_dev_cap cap,
+                                       const void *value)
+{
+
+    struct bb10_stream *stream = (struct bb10_stream*)strm;
+
+    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE &&
+        (stream->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	pjmedia_aud_dev_route route;
+	pj_status_t ret;
+
+	PJ_ASSERT_RETURN(value, PJ_EINVAL);
+
+    	route = *((pjmedia_aud_dev_route*)value);
+        /* Use the initialization function which lazy-inits the
+         * handle for routing
+         */
+    	if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER) {
+            ret = bb10_initialize_playback_ctrl(stream,true);
+        } else {
+            ret = bb10_initialize_playback_ctrl(stream,false);        	
+        }
+    	return ret;
+
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_EC &&
+	       (stream->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+	/* EC is always enabled. Silently ignore the request */
+	return PJ_SUCCESS;
+    }
+
+    TRACE_((THIS_FILE,"bb10_stream_set_cap() = PJMEDIA_EAUD_INVCAP"));
+    return PJMEDIA_EAUD_INVCAP;
+}
+
+
+/* API: start stream */
+static pj_status_t bb10_stream_start (pjmedia_aud_stream *s)
+{
+    struct bb10_stream *stream = (struct bb10_stream*)s;
+    pj_status_t status = PJ_SUCCESS;
+
+    stream->quit = 0;
+    if (stream->param.dir & PJMEDIA_DIR_PLAYBACK) {
+        status = pj_thread_create (stream->pool,
+				   "bb10sound_playback",
+				   pb_thread_func,
+				   stream,
+				   0,
+				   0,
+				   &stream->pb_thread);
+        if (status != PJ_SUCCESS)
+            return status;
+    }
+
+    if (stream->param.dir & PJMEDIA_DIR_CAPTURE) {
+        status = pj_thread_create (stream->pool,
+				   "bb10sound_playback",
+				   ca_thread_func,
+				   stream,
+				   0,
+				   0,
+				   &stream->ca_thread);
+        if (status != PJ_SUCCESS) {
+            stream->quit = PJ_TRUE;
+            pj_thread_join(stream->pb_thread);
+            pj_thread_destroy(stream->pb_thread);
+            stream->pb_thread = NULL;
+        }
+    }
+
+    return status;
+}
+
+
+/* API: stop stream */
+static pj_status_t bb10_stream_stop (pjmedia_aud_stream *s)
+{
+    struct bb10_stream *stream = (struct bb10_stream*)s;
+
+    stream->quit = 1;
+    TRACE_((THIS_FILE,"bb10_stream_stop()"));
+
+    if (stream->pb_thread) {
+        pj_thread_join (stream->pb_thread);
+        pj_thread_destroy(stream->pb_thread);
+        stream->pb_thread = NULL;
+    }
+
+    if (stream->ca_thread) {
+        pj_thread_join (stream->ca_thread);
+        pj_thread_destroy(stream->ca_thread);
+        stream->ca_thread = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t bb10_stream_destroy (pjmedia_aud_stream *s)
+{
+    struct bb10_stream *stream = (struct bb10_stream*)s;
+
+    TRACE_((THIS_FILE,"bb10_stream_destroy()"));
+
+    bb10_stream_stop (s);
+
+    pj_pool_release (stream->pool);
+
+    return PJ_SUCCESS;
+}
+
+#endif	/* PJMEDIA_AUDIO_DEV_HAS_BB10 */