From: John Crispin <john@openwrt.org>
Date: Tue, 14 Feb 2012 15:05:55 +0000 (+0000)
Subject: bump to 1.12, merge improved lantiq aud_dev driver
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=b0a11ba9fead19a793eea48795633b30ab6d6801;p=openwrt%2Fstaging%2Fnbd.git

bump to 1.12, merge improved lantiq aud_dev driver

SVN-Revision: 30520
---

diff --git a/package/pjsip/Makefile b/package/pjsip/Makefile
index b7628089e2..97a5771557 100644
--- a/package/pjsip/Makefile
+++ b/package/pjsip/Makefile
@@ -8,12 +8,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pjsip
-PKG_VERSION:=1.10
-PKG_RELEASE:=3
+PKG_VERSION:=1.12
+PKG_RELEASE:=1
 
 PKG_SOURCE:=pjproject-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=http://www.pjsip.org/release/$(PKG_VERSION)/
-PKG_MD5SUM:=e215d0637d3422d49a63c2cde6673951
+PKG_MD5SUM:=1db8e5a5dd73b216409b15afa34651a4
 
 PKG_INSTALL:=1
 PKG_BUILD_PARALLEL:=1
@@ -69,14 +69,15 @@ CONFIGURE_ARGS += \
 EXTRA_CFLAGS:=-I$(STAGING_DIR)/usr/include/drv_tapi -I$(STAGING_DIR)/usr/include/drv_vmmc
 endif
 
-Package/pjsip-oss=$(call Package/pjsip-template,oss,)
+Package/pjsip-oss=$(call Package/pjsip-template,oss,BROKEN)
 Package/pjsip-ltq-tapi=$(call Package/pjsip-template,ltq-tapi,@TARGET_lantiq +TARGET_lantiq:kmod-ltq-tapi +TARGET_lantiq:kmod-ltq-vmmc)
 
+USE_LOCAL=$(shell ls ./src/ 2>/dev/null >/dev/null && echo 1)
+ifneq ($(USE_LOCAL),)
 define Build/Prepare
-	$(PKG_UNPACK)
-	$(Build/Patch)
-	$(CP) ./src/* $(PKG_BUILD_DIR)
+	$(CP) ./src/*  $(PKG_BUILD_DIR)
 endef
+endif
 
 define Build/Configure
 	(cd $(PKG_BUILD_DIR); autoconf aconfigure.ac > aconfigure)
diff --git a/package/pjsip/patches/000-aconf.patch b/package/pjsip/patches/000-aconf.patch
deleted file mode 100644
index 46e4aad4ac..0000000000
--- a/package/pjsip/patches/000-aconf.patch
+++ /dev/null
@@ -1,45 +0,0 @@
---- a/aconfigure.ac
-+++ b/aconfigure.ac
-@@ -48,9 +48,9 @@ if test -z "$CROSS_COMPILE"; then
-     CROSS_COMPILE=`echo ${CC} | sed 's/gcc//'`
- fi
- 
--if test "$AR" = ""; then AR="${CROSS_COMPILE}ar rv"; fi
-+AR="${CROSS_COMPILE}ar rv"
- AC_SUBST(AR)
--if test "$LD" = ""; then LD="$CC"; fi
-+LD="${CROSS_COMPILE}gcc"
- AC_SUBST(LD)
- if test "$LDOUT" = ""; then LDOUT="-o"; fi
- AC_SUBST(LDOUT)
-@@ -597,6 +597,15 @@ AC_ARG_ENABLE(ext_sound,
- 		AC_MSG_RESULT([Checking if external sound is set... yes])
- 	       fi]
- 	      )
-+
-+AC_ARG_ENABLE(ltq_tapi,
-+	      AC_HELP_STRING([--enable-ltq-tapi],
-+			     [PJMEDIA will use ltq tapi backend]),
-+	      [if test "$enable_ltq_tapi" = "yes"; then
-+		[ac_pjmedia_snd=ltqtapi]
-+		AC_MSG_RESULT([Checking if external sound is set... yes])
-+	       fi]
-+	      )
- 
- dnl # Include resampling small filter
- AC_SUBST(ac_no_small_filter)
---- a/pjmedia/build/os-auto.mak.in
-+++ b/pjmedia/build/os-auto.mak.in
-@@ -118,4 +118,11 @@ ifeq ($(AC_PJMEDIA_SND),external)
- export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
- endif
- 
--
-+#
-+# Lantiq tapi backend
-+#
-+ifeq ($(AC_PJMEDIA_SND),ltqtapi)
-+export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
-+export PJMEDIA_AUDIODEV_OBJS += tapi_dev.o
-+export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE=1
-+endif
diff --git a/package/pjsip/patches/0001-configure-fixup.patch b/package/pjsip/patches/0001-configure-fixup.patch
new file mode 100644
index 0000000000..38fcea5b18
--- /dev/null
+++ b/package/pjsip/patches/0001-configure-fixup.patch
@@ -0,0 +1,62 @@
+From 01108f66fd20dcdbb9fde0dd00924ee4e8c28a7c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 28 Jan 2012 21:41:18 +0100
+Subject: [PATCH 1/3] configure fixup
+
+---
+ pjproject-1.12/aconfigure.ac                |   13 +++++++++++--
+ pjproject-1.12/pjmedia/build/os-auto.mak.in |    9 ++++++++-
+ 2 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/aconfigure.ac b/aconfigure.ac
+index 84295b5..e34fd32 100644
+--- a/aconfigure.ac
++++ b/aconfigure.ac
+@@ -48,9 +48,9 @@ if test -z "$CROSS_COMPILE"; then
+     CROSS_COMPILE=`echo ${CC} | sed 's/gcc//'`
+ fi
+ 
+-if test "$AR" = ""; then AR="${CROSS_COMPILE}ar rv"; fi
++AR="${CROSS_COMPILE}ar rv"
+ AC_SUBST(AR)
+-if test "$LD" = ""; then LD="$CC"; fi
++LD="${CROSS_COMPILE}gcc"
+ AC_SUBST(LD)
+ if test "$LDOUT" = ""; then LDOUT="-o "; fi
+ AC_SUBST(LDOUT)
+@@ -604,6 +604,15 @@ AC_ARG_ENABLE(ext_sound,
+ 	       fi]
+ 	      )
+ 
++AC_ARG_ENABLE(ltq_tapi,
++	      AC_HELP_STRING([--enable-ltq-tapi],
++			     [PJMEDIA will use ltq tapi backend]),
++	      [if test "$enable_ltq_tapi" = "yes"; then
++		[ac_pjmedia_snd=ltqtapi]
++		AC_MSG_RESULT([Checking if external sound is set... yes])
++	       fi]
++	      )
++
+ dnl # Include resampling small filter
+ AC_SUBST(ac_no_small_filter)
+ AC_ARG_ENABLE(small-filter,
+diff --git a/pjmedia/build/os-auto.mak.in b/pjmedia/build/os-auto.mak.in
+index 145f1d5..be38aeb 100644
+--- a/pjmedia/build/os-auto.mak.in
++++ b/pjmedia/build/os-auto.mak.in
+@@ -125,4 +125,11 @@ ifeq ($(AC_PJMEDIA_SND),external)
+ export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
+ endif
+ 
+-
++#
++# Lantiq tapi backend
++#
++ifeq ($(AC_PJMEDIA_SND),ltqtapi)
++export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
++export PJMEDIA_AUDIODEV_OBJS += tapi_dev.o
++export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE=1
++endif
+-- 
+1.7.7.1
+
diff --git a/package/pjsip/patches/0002-register-tapi.patch b/package/pjsip/patches/0002-register-tapi.patch
new file mode 100644
index 0000000000..56f50cb2ca
--- /dev/null
+++ b/package/pjsip/patches/0002-register-tapi.patch
@@ -0,0 +1,1345 @@
+From 455f6f2234a36aeeb97d3e05e9cbe3afad147341 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 28 Jan 2012 21:43:49 +0100
+Subject: [PATCH 2/3] register tapi
+
+---
+ .../pjmedia/src/pjmedia-audiodev/audiodev.c        |    7 +
+ .../pjmedia/src/pjmedia-audiodev/tapi_dev.c        | 1300 ++++++++++++++++++++
+ 2 files changed, 1307 insertions(+), 0 deletions(-)
+ create mode 100644 pjproject-1.12/pjmedia/src/pjmedia-audiodev/tapi_dev.c
+
+diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
+index 3b7e121..82b364c 100644
+--- a/pjmedia/src/pjmedia-audiodev/audiodev.c
++++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
+@@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf);
+ pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
+ #endif
+ 
++#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
++pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf);
++#endif
++
+ #define MAX_DRIVERS	16
+ #define MAX_DEVS	64
+ 
+@@ -409,6 +413,9 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
+ #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
+     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
+ #endif
++#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
++    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_tapi_factory;
++#endif
+ 
+     /* Initialize each factory and build the device ID list */
+     for (i=0; i<aud_subsys.drv_cnt; ++i) {
+diff --git a/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
+new file mode 100644
+index 0000000..2c65a0d
+--- /dev/null
++++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
+@@ -0,0 +1,1300 @@
++/******************************************************************************
++
++                               Copyright (c) 2010
++                            Lantiq Deutschland GmbH
++                     Am Campeon 3; 85579 Neubiberg, Germany
++
++  For licensing information, see the file 'LICENSE' in the root folder of
++  this software module.
++
++******************************************************************************/
++#include <pjmedia-audiodev/audiodev_imp.h>
++#include <pjmedia/errno.h>
++#include <pj/assert.h>
++#include <pj/pool.h>
++#include <pj/log.h>
++#include <pj/os.h>
++
++#if defined(PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE) && PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
++
++/* Linux includes */
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <ctype.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <sys/types.h>
++#include <sys/ioctl.h>
++#include <sys/select.h>
++#include <sys/time.h>
++#include <unistd.h>
++#include <poll.h>
++
++/* TAPI includes */
++#include "drv_tapi_io.h"
++#include "vmmc_io.h"
++
++/* Maximum 2 devices */
++#define TAPI_AUDIO_PORT_NUM		2
++#define TAPI_BASE_NAME			"TAPI"
++#define TAPI_LL_DEV_BASE_PATH		"/dev/vmmc"
++#define TAPI_LL_DEV_FIRMWARE_NAME	"/lib/firmware/danube_firmware.bin"
++#define TAPI_LL_BBD_NAME		"/lib/firmware/danube_bbd_fxs.bin"
++
++#define TAPI_LL_DEV_SELECT_TIMEOUT_MS		2000
++#define TAPI_LL_DEV_MAX_PACKET_SIZE		800
++#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE	12
++#define TAPI_LL_DEV_ENC_FRAME_LEN_MS		20
++#define TAPI_LL_DEV_ENC_SMPL_PER_SEC		8000
++#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS		16
++#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME		160
++#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME		(TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
++
++#define THIS_FILE	"tapi_dev.c"
++
++/* Set to 1 to enable tracing */
++#if 1
++#	define TRACE_(expr)	PJ_LOG(1,expr)
++#else
++#	define TRACE_(expr)
++#endif
++
++pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
++
++typedef struct
++{
++	pj_int32_t dev_fd;
++	pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
++	pj_int8_t data2phone_map[TAPI_AUDIO_PORT_NUM];
++} tapi_ctx;
++
++struct tapi_aud_factory
++{
++	pjmedia_aud_dev_factory	base;
++	pj_pool_t		*pool;
++	pj_pool_factory		*pf;
++	pj_uint32_t		dev_count;
++	pjmedia_aud_dev_info	*dev_info;
++	tapi_ctx		dev_ctx;
++};
++
++typedef struct tapi_aud_factory tapi_aud_factory_t;
++
++struct tapi_aud_stream
++{
++	pjmedia_aud_stream	base;
++	pj_pool_t		*pool;
++	pjmedia_aud_param	param;
++	pjmedia_aud_rec_cb	rec_cb;
++	pjmedia_aud_play_cb	play_cb;
++	void			*user_data;
++
++	pj_thread_desc		thread_desc;
++	pj_thread_t		*thread;
++	tapi_ctx		*dev_ctx;
++	pj_uint8_t		run_flag;
++	pj_timestamp		timestamp;
++};
++
++typedef struct tapi_aud_stream tapi_aud_stream_t;
++
++/* Factory prototypes */
++static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
++static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
++static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
++static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
++	unsigned index,
++	pjmedia_aud_dev_info *info);
++static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
++	unsigned index,
++	pjmedia_aud_param *param);
++static pj_status_t 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_aud_strm);
++
++/* Stream prototypes */
++static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
++	pjmedia_aud_param *param);
++static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
++	pjmedia_aud_dev_cap cap,
++	void *value);
++static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
++	pjmedia_aud_dev_cap cap,
++	const void *value);
++static pj_status_t stream_start(pjmedia_aud_stream *strm);
++static pj_status_t stream_stop(pjmedia_aud_stream *strm);
++static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
++
++static pjmedia_aud_dev_factory_op tapi_fact_op =
++{
++	&factory_init,
++	&factory_destroy,
++	&factory_get_dev_count,
++	&factory_get_dev_info,
++	&factory_default_param,
++	&factory_create_stream
++};
++
++static pjmedia_aud_stream_op tapi_strm_op =
++{
++	&stream_get_param,
++	&stream_get_cap,
++	&stream_set_cap,
++	&stream_start,
++	&stream_stop,
++	&stream_destroy
++};
++
++/* TAPI configuration */
++static struct tapi_aud_stream streams[TAPI_AUDIO_PORT_NUM];
++
++void (*tapi_digit_callback)(pj_uint8_t port, pj_uint8_t digit) = NULL;
++void (*tapi_hook_callback)(pj_uint8_t port, pj_uint8_t event) = NULL;
++
++#define TAPI_TONE_LOCALE_NONE			32
++#define TAPI_TONE_LOCALE_BUSY_CODE		33
++#define TAPI_TONE_LOCALE_CONGESTION_CODE	34
++#define TAPI_TONE_LOCALE_DIAL_CODE		35
++#define TAPI_TONE_LOCALE_RING_CODE		36
++#define TAPI_TONE_LOCALE_WAITING_CODE		37
++
++static pj_uint8_t tapi_channel_revert = 0;
++static pj_uint8_t tapi_cid_type = 0;
++static pj_uint8_t tapi_locale = 0;
++
++void tapi_revert_channels(void)
++{
++	tapi_channel_revert = 1;
++	PJ_LOG(3, (THIS_FILE, "using reverted configuration for TAPI channels"));
++}
++
++void tapi_cid_select(char *cid)
++{
++	if (!stricmp(cid, "telecordia")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_TELCORDIA;
++		PJ_LOG(3, (THIS_FILE, "using TELECORDIA configuration for TAPI CID"));
++	} else if (!stricmp(cid, "etsi_fsk")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_ETSI_FSK;
++		PJ_LOG(3, (THIS_FILE, "using ETSI FSK configuration for TAPI CID"));
++	} else if (!stricmp(cid, "etsi_dtmf")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_ETSI_DTMF;
++		PJ_LOG(3, (THIS_FILE, "using ETSI DTMF configuration for TAPI CID"));
++	} else if (!stricmp(cid, "sin")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_SIN;
++		PJ_LOG(3, (THIS_FILE, "using SIN CID configuration for TAPI CID"));
++	} else if (!stricmp(cid, "ntt")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_NTT;
++		PJ_LOG(3, (THIS_FILE, "using NTT configuration for TAPI CID"));
++	} else if (!stricmp(cid, "kpn_dtmf")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF;
++		PJ_LOG(3, (THIS_FILE, "using KPN DTMF configuration for TAPI CID"));
++	} else if (!stricmp(cid, "kpn_dtmf_fsk")) {
++		tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF_FSK;
++		PJ_LOG(3, (THIS_FILE, "using KPN DTMF FSK configuration for TAPI CID"));
++	} 
++}
++
++void tapi_locale_select(char *country)
++{
++	IFX_TAPI_TONE_t tone;
++	pj_status_t status;
++	pj_uint8_t c;
++
++	tapi_locale = 1;
++
++	if (!stricmp(country, "croatia")) {
++		PJ_LOG(3, (THIS_FILE, "using localized tones for Croatia"));
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 500;
++		tone.simple.cadence[1] = 500;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 250;
++		tone.simple.cadence[1] = 250;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 200;
++		tone.simple.cadence[1] = 300;
++		tone.simple.cadence[2] = 700;
++		tone.simple.cadence[3] = 800;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 1000;
++		tone.simple.cadence[1] = 4000;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 300;
++		tone.simple.cadence[1] = 8000;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++	} else if (!stricmp(country, "germany")) {
++		PJ_LOG(3, (THIS_FILE, "using localized tones for Germany"));
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 480;
++		tone.simple.cadence[1] = 480;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 240;
++		tone.simple.cadence[1] = 240;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 1000;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 1000;
++		tone.simple.cadence[1] = 4000;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++
++		memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++		tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++		tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
++		tone.simple.freqA = 425;
++		tone.simple.levelA = 0;
++		tone.simple.cadence[0] = 200;
++		tone.simple.cadence[1] = 200;
++		tone.simple.cadence[2] = 200;
++		tone.simple.cadence[3] = 5000;
++		tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
++		tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
++		tone.simple.loop = 0;
++		tone.simple.pause = 0;
++		for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++			status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++			if (status != PJ_SUCCESS)
++				TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++		}
++	}
++}
++
++static pj_int32_t
++tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
++{
++	char devname[128] = { 0 };
++	pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
++	return open((const char*)devname, O_RDWR, 0644);
++}
++
++static pj_status_t
++tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
++{
++	pj_status_t status = PJ_SUCCESS;
++	FILE *fd;
++	struct stat file_stat;
++
++	fd = fopen(pPath, "rb");
++	if (fd == NULL) {
++		TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath));
++		return PJ_EUNKNOWN;
++	}
++
++	if (stat(pPath, &file_stat) != 0) {
++		TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath));
++		return PJ_EUNKNOWN;
++	}
++
++	*ppBuf = malloc(file_stat.st_size);
++	if (*ppBuf == NULL) {
++		TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath));
++		status = PJ_EUNKNOWN;
++		goto on_exit;
++	}
++
++	if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
++		TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
++		status = PJ_EUNKNOWN;
++		goto on_exit;
++	}
++
++	*pBufSz = file_stat.st_size;
++
++on_exit:
++	if (fd != NULL)
++		fclose(fd);
++
++	if (*ppBuf != NULL && status != PJ_SUCCESS)
++		free(*ppBuf);
++
++	return status;
++}
++
++static void
++tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
++{
++	if (pBuf != NULL)
++		free(pBuf);
++}
++
++static pj_status_t
++tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
++{
++	pj_status_t status = PJ_SUCCESS;
++	pj_uint8_t *pFirmware = NULL;
++	pj_uint32_t binSz = 0;
++	VMMC_IO_INIT vmmc_io_init;
++
++	status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
++		return PJ_EUNKNOWN;
++	}
++
++	memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
++	vmmc_io_init.pPRAMfw = pFirmware;
++	vmmc_io_init.pram_size = binSz;
++
++	status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
++	if (status != PJ_SUCCESS)
++		TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!"));
++
++	tapi_dev_binary_buffer_delete(pFirmware);
++
++	return status;
++}
++
++/* NOT USED */
++#if 0
++static int
++tapi_dev_bbd_download(int fd, const char *pPath)
++{
++	int status = PJ_SUCCESS;
++	unsigned char *pFirmware = NULL;
++	unsigned int binSz = 0;
++	VMMC_DWLD_t bbd_data;
++
++
++	/* Create binary buffer */
++	status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
++		return status;
++	}
++
++	/* Download Voice Firmware */
++	memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
++	bbd_data.buf = pFirmware;
++	bbd_data.size = binSz;
++
++	status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
++	}
++
++	/* Delete binary buffer */
++	tapi_dev_binary_buffer_delete(pFirmware);
++
++	return status;
++}
++#endif
++
++static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
++{
++	pj_uint8_t c, hook_status;
++	IFX_TAPI_TONE_t tone;
++	IFX_TAPI_DEV_START_CFG_t tapistart;
++	IFX_TAPI_MAP_DATA_t datamap;
++	IFX_TAPI_ENC_CFG_t enc_cfg;
++	IFX_TAPI_LINE_VOLUME_t line_vol;
++	IFX_TAPI_WLEC_CFG_t lec_cfg;
++	IFX_TAPI_JB_CFG_t jb_cfg;
++	IFX_TAPI_CID_CFG_t cid_cfg;
++	pj_status_t status;
++
++	/* Open device */
++	f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
++
++	if (f->dev_ctx.dev_fd < 0) {
++		TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++		if (tapi_channel_revert)
++			ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, c + 1);
++		else
++			ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
++
++		if (f->dev_ctx.dev_fd < 0) {
++			TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
++			return PJ_EUNKNOWN;
++		}
++		if (tapi_channel_revert)
++			f->dev_ctx.data2phone_map[c] = c & 0x1 ? 1 : 0;
++		else
++			f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
++	}
++
++	status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	/* Download coefficients */
++	/*
++	status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
++		return PJ_EUNKNOWN;
++	}
++	*/
++
++	memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
++	tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
++
++	/* Start TAPI */
++	status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
++	if (status != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
++		return PJ_EUNKNOWN;
++	}
++
++
++	/* OpenWrt default tone */
++	memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
++	tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
++	tone.simple.index = TAPI_TONE_LOCALE_NONE;
++	tone.simple.freqA = 400;
++	tone.simple.levelA = 0;
++	tone.simple.freqB = 450;
++	tone.simple.levelB = 0;
++	tone.simple.freqC = 550;
++	tone.simple.levelC = 0;
++	tone.simple.freqD = 600;
++	tone.simple.levelD = 0;
++	tone.simple.cadence[0] = 100;
++	tone.simple.cadence[1] = 150;
++	tone.simple.cadence[2] = 100;
++	tone.simple.cadence[3] = 150;
++	tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA | IFX_TAPI_TONE_FREQB;
++	tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
++	tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQC | IFX_TAPI_TONE_FREQD;
++	tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
++	tone.simple.loop = 0;
++	tone.simple.pause = 0;
++	for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
++		/* OpenWrt default tone */
++		status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
++		if (status != PJ_SUCCESS)
++			TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
++
++		/* Perform mapping */
++		memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
++		datamap.nDstCh = f->dev_ctx.data2phone_map[c];
++		datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
++
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Set Line feed */
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Configure encoder for linear stream */
++		memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
++		enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
++		enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8;
++
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Suppress TAPI volume, otherwise PJSIP starts autogeneration */
++		memset(&line_vol, 0, sizeof(line_vol));
++		line_vol.nGainRx = -8;
++		line_vol.nGainTx = -8;
++
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Configure line echo canceller */
++		memset(&lec_cfg, 0, sizeof(lec_cfg));
++	        lec_cfg.nType = IFX_TAPI_WLEC_TYPE_NFE;
++	        lec_cfg.bNlp = IFX_TAPI_LEC_NLP_OFF;
++
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_WLEC_PHONE_CFG_SET, &lec_cfg);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_WLEC_PHONE_CFG_SET ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Configure jitter buffer */
++		memset(&jb_cfg, 0, sizeof(jb_cfg));
++		jb_cfg.nJbType = IFX_TAPI_JB_TYPE_ADAPTIVE;
++		jb_cfg.nPckAdpt = IFX_TAPI_JB_PKT_ADAPT_VOICE;
++		jb_cfg.nLocalAdpt = IFX_TAPI_JB_LOCAL_ADAPT_ON;
++		jb_cfg.nScaling = 0x10;
++		jb_cfg.nInitialSize = 0x2d0;
++		jb_cfg.nMinSize = 0x50;
++		jb_cfg.nMaxSize = 0x5a0;
++
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_JB_CFG_SET, &jb_cfg);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_JB_CFG_SET ioctl failed"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* Configure Caller ID type */
++		if (tapi_cid_type) {
++			memset(&cid_cfg, 0, sizeof(cid_cfg));
++			cid_cfg.nStandard = tapi_cid_type;
++			status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cfg);
++			if (status != PJ_SUCCESS) {
++				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
++				return PJ_EUNKNOWN;
++			}
++		}
++
++		/* check hook status */
++		hook_status = 0;
++		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
++		if (status != PJ_SUCCESS) {
++			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
++			return PJ_EUNKNOWN;
++		}
++
++		/* if off hook do initialization */
++		if (hook_status) {
++			status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
++			if (status != PJ_SUCCESS) {
++				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
++				return PJ_EUNKNOWN;
++			}
++			status = ioctl(c, IFX_TAPI_ENC_START, 0);
++			if (status != PJ_SUCCESS) {
++				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
++				return PJ_EUNKNOWN;
++			}
++
++			status = ioctl(c, IFX_TAPI_DEC_START, 0);
++			if (status != PJ_SUCCESS) {
++				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
++				return PJ_EUNKNOWN;
++			}
++		}
++	}
++
++	return status;
++}
++
++static pj_status_t
++tapi_dev_stop(tapi_aud_factory_t *f)
++{
++	pj_status_t status = PJ_SUCCESS;
++	pj_uint8_t c;
++
++	if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
++		status = PJ_EUNKNOWN;
++	}
++
++	close(f->dev_ctx.dev_fd);
++	for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
++		close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
++
++	return status;
++}
++
++static pj_status_t
++tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
++{
++	if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
++			start ? "START" : "STOP"));
++		return PJ_EUNKNOWN;
++	}
++
++	if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
++			start ? "START" : "STOP"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
++{
++	PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
++
++	if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
++		IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	/* enc/dec stop */
++	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
++{
++	PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
++
++	if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
++		IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	/* enc/dec stop */
++	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
++{
++	PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
++
++	if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
++			IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	/* enc/dec stop */
++	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++tapi_dev_event_handler(tapi_aud_stream_t *stream)
++{
++	IFX_TAPI_EVENT_t tapiEvent;
++	tapi_ctx *dev_ctx = stream->dev_ctx;
++	pj_status_t status = PJ_SUCCESS;
++	unsigned int i;
++
++	for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
++		memset (&tapiEvent, 0, sizeof(tapiEvent));
++		tapiEvent.ch = dev_ctx->data2phone_map[i];
++		status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
++
++		if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
++			switch(tapiEvent.id) {
++			case IFX_TAPI_EVENT_FXS_ONHOOK:
++				status = tapi_dev_event_on_hook(dev_ctx, i);
++				if(tapi_hook_callback)
++					tapi_hook_callback(i, 0);
++				break;
++			case IFX_TAPI_EVENT_FXS_OFFHOOK:
++				status = tapi_dev_event_off_hook(dev_ctx, i);
++				if(tapi_hook_callback)
++					tapi_hook_callback(i, 1);
++				break;
++			case IFX_TAPI_EVENT_DTMF_DIGIT:
++				if(tapi_digit_callback)
++					tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
++				break;
++			case IFX_TAPI_EVENT_COD_DEC_CHG:
++			case IFX_TAPI_EVENT_TONE_GEN_END:
++			case IFX_TAPI_EVENT_CID_TX_SEQ_END:
++				break;
++			default:
++				PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
++				break;
++			}
++		}
++	}
++
++	return status;
++}
++
++static pj_status_t
++tapi_dev_data_handler(tapi_aud_stream_t *stream) {
++	pj_status_t status = PJ_SUCCESS;
++	tapi_ctx *dev_ctx = stream->dev_ctx;
++	pj_uint32_t dev_idx = stream->param.rec_id;
++	pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
++	pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
++	pjmedia_frame frame_rec, frame_play;
++	pj_int32_t ret;
++
++	/* Get data from driver */
++	ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
++	if (ret < 0) {
++		TRACE_((THIS_FILE, "ERROR - no data available from device!"));
++		return PJ_EUNKNOWN;
++	}
++
++	if (ret > 0) {
++		frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
++		frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
++		frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
++		frame_rec.timestamp.u64 = stream->timestamp.u64;
++
++		status = stream->rec_cb(stream->user_data, &frame_rec);
++		if (status != PJ_SUCCESS)
++			PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
++
++		frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
++		frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
++		frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
++		frame_play.timestamp.u64 = stream->timestamp.u64;
++
++		status = (*stream->play_cb)(stream->user_data, &frame_play);
++		if (status != PJ_SUCCESS) {
++			PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
++		} else {
++			memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
++
++			ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
++
++			if (ret < 0) {
++				PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
++				return PJ_EUNKNOWN;
++			}
++
++			if (ret == 0) {
++				PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
++				return PJ_EUNKNOWN;
++			}
++		}
++
++		stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static int
++PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
++	tapi_ctx *dev_ctx = streams[0].dev_ctx;
++	pj_uint32_t sretval;
++	struct pollfd fds[3];
++
++	PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
++
++	streams[0].run_flag = 1;
++	streams[1].run_flag = 1;
++
++	fds[0].fd = dev_ctx->dev_fd;
++	fds[0].events = POLLIN;
++	fds[1].fd = dev_ctx->ch_fd[0];
++	fds[1].events = POLLIN;
++	fds[2].fd = dev_ctx->ch_fd[1];
++	fds[2].events = POLLIN;
++
++	while(1)
++	{
++		sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
++
++		if (!streams[0].run_flag && !streams[0].run_flag)
++			break;
++		if (sretval <= 0)
++			continue;
++
++		if (fds[0].revents == POLLIN) {
++			if (tapi_dev_event_handler(&streams[0]) != PJ_SUCCESS) {
++				PJ_LOG(1, (THIS_FILE, "TAPI: event hanldler failed"));
++				break;
++			}
++		}
++
++		if (fds[1].revents == POLLIN) {
++			if (tapi_dev_data_handler(&streams[0]) != PJ_SUCCESS) {
++				PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
++				break;
++			}
++		}
++
++		if (fds[2].revents == POLLIN) {
++			if (tapi_dev_data_handler(&streams[1]) != PJ_SUCCESS) {
++				PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
++				break;
++			}
++		}
++	}
++	PJ_LOG(1, (THIS_FILE, "TAPI: thread stopping..."));
++
++	return 0;
++}
++
++/* Factory operations */
++
++pjmedia_aud_dev_factory*
++pjmedia_tapi_factory(pj_pool_factory *pf) {
++	struct tapi_aud_factory *f;
++	pj_pool_t *pool;
++
++	TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
++
++	pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
++	f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
++	f->pf = pf;
++	f->pool = pool;
++	f->base.op = &tapi_fact_op;
++
++	return &f->base;
++}
++
++static pj_status_t
++factory_init(pjmedia_aud_dev_factory *f)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++	pj_uint8_t i;
++
++	TRACE_((THIS_FILE, "factory_init()"));
++
++	af->dev_count = TAPI_AUDIO_PORT_NUM;
++	af->dev_info = (pjmedia_aud_dev_info*)
++	pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
++	for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
++		pj_ansi_sprintf(af->dev_info[i].name,"%s_%02d", TAPI_BASE_NAME, i);
++		af->dev_info[i].input_count = af->dev_info[i].output_count = 1;
++		af->dev_info[i].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
++		pj_ansi_strcpy(af->dev_info[i].driver, "/dev/vmmc");
++		af->dev_info[i].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
++			PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
++			PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
++		af->dev_info[i].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
++	}
++	if (tapi_dev_start(af) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++factory_destroy(pjmedia_aud_dev_factory *f)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++	pj_pool_t *pool;
++	pj_status_t status = PJ_SUCCESS;
++
++	TRACE_((THIS_FILE, "factory_destroy()"));
++
++	if (tapi_dev_stop(af) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
++		status = PJ_EUNKNOWN;
++	}
++	pool = af->pool;
++	af->pool = NULL;
++	pj_pool_release(pool);
++
++	return status;
++}
++
++static unsigned
++factory_get_dev_count(pjmedia_aud_dev_factory *f)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++	TRACE_((THIS_FILE, "factory_get_dev_count()"));
++
++	return af->dev_count;
++}
++
++static pj_status_t
++factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++
++	TRACE_((THIS_FILE, "factory_get_dev_info()"));
++	PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
++
++	pj_memcpy(info, &af->dev_info[index], sizeof(*info));
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++	struct pjmedia_aud_dev_info *di = &af->dev_info[index];
++
++	TRACE_((THIS_FILE, "factory_default_param."));
++	PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
++
++	pj_bzero(param, sizeof(*param));
++	if (di->input_count && di->output_count) {
++		param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
++		param->rec_id = index;
++		param->play_id = index;
++	} else if (di->input_count) {
++		param->dir = PJMEDIA_DIR_CAPTURE;
++		param->rec_id = index;
++		param->play_id = PJMEDIA_AUD_INVALID_DEV;
++	} else if (di->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 = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
++	param->channel_count = 1;
++	param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
++	param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
++	param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
++	param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
++
++	return PJ_SUCCESS;
++}
++
++
++static pj_status_t
++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_aud_strm)
++{
++	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
++	pj_pool_t *pool;
++	pj_status_t status;
++	int id = param->rec_id;
++	struct tapi_aud_stream *strm = &streams[param->rec_id];
++	TRACE_((THIS_FILE, "factory_create_stream() rec_id:%d play_id:%d", param->rec_id, param->play_id));
++
++	/* Can only support 16bits per sample */
++	PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
++	PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
++	PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
++
++	/* Can only support bidirectional stream */
++	PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
++
++	if (id == 0) {
++		/* Initialize our stream data */
++		pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
++		PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
++
++		strm->pool = pool;
++	} else {
++		pool = strm->pool = streams[0].pool;
++	}
++
++	strm->rec_cb = rec_cb;
++	strm->play_cb = play_cb;
++	strm->user_data = user_data;
++
++	pj_memcpy(&strm->param, param, sizeof(*param));
++
++	if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
++		strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
++	}
++
++	strm->timestamp.u64 = 0;
++	strm->dev_ctx = &(af->dev_ctx);
++
++	/* Create and start the thread */
++	if (id == 1) {
++		status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, &streams[0].thread);
++		if (status != PJ_SUCCESS) {
++			stream_destroy(&strm->base);
++			return status;
++		}
++	}
++
++	/* Done */
++	strm->base.op = &tapi_strm_op;
++	*p_aud_strm = &strm->base;
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
++{
++	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
++
++	PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
++	pj_memcpy(pi, &strm->param, sizeof(*pi));
++
++	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
++				&pi->output_vol) == PJ_SUCCESS)
++		pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
++
++	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
++				&pi->output_latency_ms) == PJ_SUCCESS)
++		pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
++
++	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
++				&pi->input_latency_ms) == PJ_SUCCESS)
++		pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
++{
++	// struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
++{
++	// struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_start(pjmedia_aud_stream *s)
++{
++	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
++	pj_uint32_t dev_idx;
++
++	TRACE_((THIS_FILE, "stream_start()"));
++
++	dev_idx = strm->param.rec_id;
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_stop(pjmedia_aud_stream *s)
++{
++	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
++	tapi_ctx *dev_ctx = strm->dev_ctx;
++	pj_uint32_t dev_idx;
++
++	TRACE_((THIS_FILE, "stream_stop()"));
++	dev_idx = strm->param.rec_id;
++
++	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++static pj_status_t
++stream_destroy(pjmedia_aud_stream *s)
++{
++	pj_status_t state = PJ_SUCCESS;
++	struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
++	pj_pool_t *pool;
++
++	PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
++	TRACE_((THIS_FILE, "stream_destroy()"));
++
++	stream_stop(&stream->base);
++	stream->run_flag = 0;
++
++	if (stream->thread)
++	{
++		pj_thread_join(stream->thread);
++		pj_thread_destroy(stream->thread);
++		stream->thread = NULL;
++	}
++
++	pool = stream->pool;
++	pj_bzero(stream, sizeof(stream));
++	pj_pool_release(pool);
++
++	return state;
++}
++
++pj_status_t
++tapi_hook_status(pj_uint8_t port, pj_int32_t *status)
++{
++	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
++
++	if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
++			!= PJ_SUCCESS) {
++		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
++		return PJ_EUNKNOWN;
++	}
++
++	return PJ_SUCCESS;
++}
++
++pj_status_t
++tapi_ring(pj_uint8_t port, pj_uint8_t state, char *caller_number)
++{
++	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
++
++	if (state) {
++		if (tapi_cid_type && caller_number) {
++			IFX_TAPI_CID_MSG_t cid_msg;
++			IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
++			memset(&cid_msg, 0, sizeof(cid_msg));
++			memset(&cid_msg_el, 0, sizeof(cid_msg_el));
++
++			cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
++			cid_msg_el[0].string.len = strlen(caller_number);
++			strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
++
++			cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
++			cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
++			cid_msg.nMsgElements = 1;
++			cid_msg.message = cid_msg_el;
++			ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
++		} else {
++			ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
++		}
++	} else {
++		ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
++	}
++
++	return PJ_SUCCESS;
++}
++
++pj_status_t
++tapi_tone(pj_uint8_t port, pj_uint8_t code)
++{
++	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
++
++	if (tapi_locale && code)
++		ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, code);
++	else if (code)
++		ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, TAPI_TONE_LOCALE_NONE);
++	else
++		ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
++
++	return PJ_SUCCESS;
++}
++
++#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */
+-- 
+1.7.7.1
+
diff --git a/package/pjsip/patches/0003-adds-PJ_DEF-pj_status_t-pjsua_add_snd_port-int-id.patch b/package/pjsip/patches/0003-adds-PJ_DEF-pj_status_t-pjsua_add_snd_port-int-id.patch
new file mode 100644
index 0000000000..8e9b604147
--- /dev/null
+++ b/package/pjsip/patches/0003-adds-PJ_DEF-pj_status_t-pjsua_add_snd_port-int-id.patch
@@ -0,0 +1,229 @@
+From 1e0d5dbf8b7714dfd490add0e2b507fd513414f3 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 3 Feb 2012 21:45:08 +0100
+Subject: [PATCH 3/3] adds PJ_DEF(pj_status_t) pjsua_add_snd_port(int id)
+
+---
+ pjproject-1.12/pjsip/include/pjsua-lib/pjsua.h     |    2 +
+ .../pjsip/include/pjsua-lib/pjsua_internal.h       |    4 +-
+ pjproject-1.12/pjsip/src/pjsua-lib/pjsua_media.c   |   69 ++++++++++++++------
+ 3 files changed, 54 insertions(+), 21 deletions(-)
+
+diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
+index 85dbbbb..ad3e020 100644
+--- a/pjsip/include/pjsua-lib/pjsua.h
++++ b/pjsip/include/pjsua-lib/pjsua.h
+@@ -1543,6 +1543,8 @@ PJ_DECL(pjmedia_endpt*) pjsua_get_pjmedia_endpt(void);
+ PJ_DECL(pj_pool_factory*) pjsua_get_pool_factory(void);
+ 
+ 
++PJ_DECL(pj_status_t) pjsua_add_snd_port(int id, pjsua_conf_port_id *p_id);
++
+ 
+ /*****************************************************************************
+  * Utilities.
+diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
+index 6c27826..4ba91ed 100644
+--- a/pjsip/include/pjsua-lib/pjsua_internal.h
++++ b/pjsip/include/pjsua-lib/pjsua_internal.h
+@@ -261,6 +261,8 @@ typedef struct pjsua_stun_resolve
+ } pjsua_stun_resolve;
+ 
+ 
++#define MAX_PORT	2
++
+ /**
+  * Global pjsua application data.
+  */
+@@ -336,7 +338,7 @@ struct pjsua_data
+     pj_bool_t		 aud_open_cnt;/**< How many # device is opened	*/
+     pj_bool_t		 no_snd;    /**< No sound (app will manage it)	*/
+     pj_pool_t		*snd_pool;  /**< Sound's private pool.		*/
+-    pjmedia_snd_port	*snd_port;  /**< Sound port.			*/
++    pjmedia_snd_port	*snd_port[MAX_PORT];  /**< Sound port.			*/
+     pj_timer_entry	 snd_idle_timer;/**< Sound device idle timer.	*/
+     pjmedia_master_port	*null_snd;  /**< Master port for null sound.	*/
+     pjmedia_port	*null_port; /**< Null port.			*/
+diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
+index 7d53cad..8a882f3 100644
+--- a/pjsip/src/pjsua-lib/pjsua_media.c
++++ b/pjsip/src/pjsua-lib/pjsua_media.c
+@@ -588,7 +588,7 @@ static void check_snd_dev_idle()
+      * It is idle when there is no port connection in the bridge and
+      * there is no active call.
+      */
+-    if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && 
++    if ((pjsua_var.snd_port[0]!=NULL || pjsua_var.null_snd!=NULL) && 
+ 	pjsua_var.snd_idle_timer.id == PJ_FALSE &&
+ 	pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 &&
+ 	call_cnt == 0 &&
+@@ -2009,7 +2009,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
+ 	pj_assert(status == PJ_SUCCESS);
+ 
+ 	/* Check if sound device is instantiated. */
+-	need_reopen = (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 
++	need_reopen = (pjsua_var.snd_port[0]==NULL && pjsua_var.null_snd==NULL && 
+ 		      !pjsua_var.no_snd);
+ 
+ 	/* Check if sound device need to reopen because it needs to modify 
+@@ -2067,7 +2067,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source,
+ 	/* The bridge version */
+ 
+ 	/* Create sound port if none is instantiated */
+-	if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 
++	if (pjsua_var.snd_port[0]==NULL && pjsua_var.null_snd==NULL && 
+ 	    !pjsua_var.no_snd) 
+ 	{
+ 	    pj_status_t status;
+@@ -2679,9 +2679,9 @@ static pj_status_t update_initial_aud_param()
+     pjmedia_aud_param param;
+     pj_status_t status;
+ 
+-    PJ_ASSERT_RETURN(pjsua_var.snd_port != NULL, PJ_EBUG);
++    PJ_ASSERT_RETURN(pjsua_var.snd_port[0] != NULL, PJ_EBUG);
+ 
+-    strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
++    strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]);
+ 
+     status = pjmedia_aud_stream_get_param(strm, &param);
+     if (status != PJ_SUCCESS) {
+@@ -2747,7 +2747,7 @@ static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
+ 	      1000 / param->base.clock_rate));
+ 
+     status = pjmedia_snd_port_create2( pjsua_var.snd_pool, 
+-				       param, &pjsua_var.snd_port);
++				       param, &pjsua_var.snd_port[0]);
+     if (status != PJ_SUCCESS)
+ 	return status;
+ 
+@@ -2805,13 +2805,13 @@ static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
+     }
+ 
+     /* Connect sound port to the bridge */
+-    status = pjmedia_snd_port_connect(pjsua_var.snd_port, 	 
++    status = pjmedia_snd_port_connect(pjsua_var.snd_port[0], 	 
+ 				      conf_port ); 	 
+     if (status != PJ_SUCCESS) { 	 
+ 	pjsua_perror(THIS_FILE, "Unable to connect conference port to "
+ 			        "sound device", status); 	 
+-	pjmedia_snd_port_destroy(pjsua_var.snd_port); 	 
+-	pjsua_var.snd_port = NULL; 	 
++	pjmedia_snd_port_destroy(pjsua_var.snd_port[0]); 	 
++	pjsua_var.snd_port[0] = NULL; 	 
+ 	return status; 	 
+     }
+ 
+@@ -2826,7 +2826,7 @@ static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
+ 	pjmedia_aud_param si;
+         pj_str_t tmp;
+ 
+-	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
++	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]);
+ 	status = pjmedia_aud_stream_get_param(strm, &si);
+ 	if (status == PJ_SUCCESS)
+ 	    status = pjmedia_aud_dev_get_info(si.rec_id, &rec_info);
+@@ -2869,12 +2869,12 @@ static pj_status_t open_snd_dev(pjmedia_snd_port_param *param)
+ static void close_snd_dev(void)
+ {
+     /* Close sound device */
+-    if (pjsua_var.snd_port) {
++    if (pjsua_var.snd_port[0]) {
+ 	pjmedia_aud_dev_info cap_info, play_info;
+ 	pjmedia_aud_stream *strm;
+ 	pjmedia_aud_param param;
+ 
+-	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
++	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]);
+ 	pjmedia_aud_stream_get_param(strm, &param);
+ 
+ 	if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS)
+@@ -2886,9 +2886,9 @@ static void close_snd_dev(void)
+ 			     "%s sound capture device",
+ 			     play_info.name, cap_info.name));
+ 
+-	pjmedia_snd_port_disconnect(pjsua_var.snd_port);
+-	pjmedia_snd_port_destroy(pjsua_var.snd_port);
+-	pjsua_var.snd_port = NULL;
++	pjmedia_snd_port_disconnect(pjsua_var.snd_port[0]);
++	pjmedia_snd_port_destroy(pjsua_var.snd_port[0]);
++	pjsua_var.snd_port[0] = NULL;
+     }
+ 
+     /* Close null sound device */
+@@ -2968,6 +2968,35 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
+     return PJ_SUCCESS;
+ }
+ 
++PJ_DEF(pj_status_t) pjsua_add_snd_port(int id, pjsua_conf_port_id *p_id)
++{
++	unsigned alt_cr_cnt = 1;
++	unsigned alt_cr = 0;
++	pj_status_t status = -1;
++	pjmedia_snd_port_param param;
++	unsigned samples_per_frame;
++	pjmedia_port *port;
++	const pj_str_t name = pj_str("tapi2");
++	alt_cr = pjsua_var.media_cfg.clock_rate;
++	samples_per_frame = alt_cr *
++			    pjsua_var.media_cfg.audio_frame_ptime *
++			    pjsua_var.media_cfg.channel_count / 1000;
++	status = create_aud_param(&param.base,
++				pjsua_var.play_dev,
++				pjsua_var.cap_dev,
++				alt_cr,
++				pjsua_var.media_cfg.channel_count,
++				samples_per_frame, 16);
++	if (status != PJ_SUCCESS)
++		return status;
++	param.base.rec_id = id;
++	param.base.play_id = id;
++	param.options = 0;
++	status = pjmedia_snd_port_create2(pjsua_var.snd_pool,
++				       &param, &pjsua_var.snd_port[id]);
++	return PJ_SUCCESS;
++}
++
+ 
+ /*
+  * Get currently active sound devices. If sound devices has not been created
+@@ -3054,8 +3083,8 @@ PJ_DEF(pj_status_t) pjsua_set_ec(unsigned tail_ms, unsigned options)
+ {
+     pjsua_var.media_cfg.ec_tail_len = tail_ms;
+ 
+-    if (pjsua_var.snd_port)
+-	return pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.pool,
++    if (pjsua_var.snd_port[0])
++	return pjmedia_snd_port_set_ec( pjsua_var.snd_port[0], pjsua_var.pool,
+ 					tail_ms, options);
+     
+     return PJ_SUCCESS;
+@@ -3077,7 +3106,7 @@ PJ_DEF(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms)
+  */
+ PJ_DEF(pj_bool_t) pjsua_snd_is_active(void)
+ {
+-    return pjsua_var.snd_port != NULL;
++    return pjsua_var.snd_port[0] != NULL;
+ }
+ 
+ 
+@@ -3099,7 +3128,7 @@ PJ_DEF(pj_status_t) pjsua_snd_set_setting( pjmedia_aud_dev_cap cap,
+     if (pjsua_snd_is_active()) {
+ 	pjmedia_aud_stream *strm;
+ 	
+-	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
++	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]);
+ 	status = pjmedia_aud_stream_set_cap(strm, cap, pval);
+     } else {
+ 	status = PJ_SUCCESS;
+@@ -3137,7 +3166,7 @@ PJ_DEF(pj_status_t) pjsua_snd_get_setting( pjmedia_aud_dev_cap cap,
+ 	/* Sound is active, retrieve from device directly */
+ 	pjmedia_aud_stream *strm;
+ 	
+-	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
++	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port[0]);
+ 	return pjmedia_aud_stream_get_cap(strm, cap, pval);
+     } else {
+ 	/* Otherwise retrieve from internal param */
+-- 
+1.7.7.1
+
diff --git a/package/pjsip/patches/100-pjsua_acc__snprintf.patch b/package/pjsip/patches/100-pjsua_acc__snprintf.patch
deleted file mode 100644
index 929ecc94dd..0000000000
--- a/package/pjsip/patches/100-pjsua_acc__snprintf.patch
+++ /dev/null
@@ -1,92 +0,0 @@
---- a/pjsip/src/pjsua-lib/pjsua_acc.c
-+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
-@@ -511,7 +511,7 @@ PJ_DEF(pj_status_t) pjsua_acc_add_local(
- 		     "<sip:%s%.*s%s:%d%s>", 
- 		     beginquote,
- 		     (int)t->local_name.host.slen,
--		     t->local_name.host.ptr,
-+		     t->local_name.host.slen ? t->local_name.host.ptr : "",
- 		     endquote,
- 		     t->local_name.port,
- 		     transport_param);
-@@ -1327,19 +1327,19 @@ static pj_bool_t acc_check_nat_addr(pjsu
- 	len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE,
- 			       "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s%s>%.*s",
- 			       (int)acc->user_part.slen,
--			       acc->user_part.ptr,
-+			       acc->user_part.slen ? acc->user_part.ptr : "",
- 			       (acc->user_part.slen? "@" : ""),
- 			       beginquote,
- 			       (int)via_addr->slen,
--			       via_addr->ptr,
-+			       via_addr->slen ? via_addr->ptr : "",
- 			       endquote,
- 			       rport,
- 			       tp->type_name,
- 			       (int)acc->cfg.contact_uri_params.slen,
--			       acc->cfg.contact_uri_params.ptr,
-+			       acc->cfg.contact_uri_params.slen ? acc->cfg.contact_uri_params.ptr : "",
- 			       ob,
- 			       (int)acc->cfg.contact_params.slen,
--			       acc->cfg.contact_params.ptr);
-+			       acc->cfg.contact_params.slen ? acc->cfg.contact_params.ptr : "");
- 	if (len < 1) {
- 	    PJ_LOG(1,(THIS_FILE, "URI too long"));
- 	    pj_pool_release(pool);
-@@ -2467,23 +2467,23 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac
-     contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
- 				     "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
- 				     (int)acc->display.slen,
--				     acc->display.ptr,
-+				     acc->display.slen ? acc->display.ptr : "",
- 				     (acc->display.slen?" " : ""),
- 				     (secure ? PJSUA_SECURE_SCHEME : "sip"),
- 				     (int)acc->user_part.slen,
--				     acc->user_part.ptr,
-+				     acc->user_part.slen ? acc->user_part.ptr : "",
- 				     (acc->user_part.slen?"@":""),
- 				     beginquote,
- 				     (int)local_addr.slen,
--				     local_addr.ptr,
-+				     local_addr.slen ? local_addr.ptr : "",
- 				     endquote,
- 				     local_port,
- 				     transport_param,
- 				     (int)acc->cfg.contact_uri_params.slen,
--				     acc->cfg.contact_uri_params.ptr,
-+				     acc->cfg.contact_uri_params.slen ? acc->cfg.contact_uri_params.ptr : "",
- 				     ob,
- 				     (int)acc->cfg.contact_params.slen,
--				     acc->cfg.contact_params.ptr);
-+				     acc->cfg.contact_params.slen ? acc->cfg.contact_params.ptr : "");
- 
-     return PJ_SUCCESS;
- }
-@@ -2625,22 +2625,22 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas
-     contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
- 				     "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>%.*s",
- 				     (int)acc->display.slen,
--				     acc->display.ptr,
-+				     acc->display.slen ? acc->display.ptr : "",
- 				     (acc->display.slen?" " : ""),
- 				     (secure ? PJSUA_SECURE_SCHEME : "sip"),
- 				     (int)acc->user_part.slen,
--				     acc->user_part.ptr,
-+				     acc->user_part.slen ? acc->user_part.ptr : "",
- 				     (acc->user_part.slen?"@":""),
- 				     beginquote,
- 				     (int)local_addr.slen,
--				     local_addr.ptr,
-+				     local_addr.slen ? local_addr.ptr : "",
- 				     endquote,
- 				     local_port,
- 				     transport_param,
- 				     (int)acc->cfg.contact_uri_params.slen,
--				     acc->cfg.contact_uri_params.ptr,
-+				     acc->cfg.contact_uri_params.slen ? acc->cfg.contact_uri_params.ptr : "",
- 				     (int)acc->cfg.contact_params.slen,
--				     acc->cfg.contact_params.ptr);
-+				     acc->cfg.contact_params.slen ? acc->cfg.contact_params.ptr : "");
- 
-     return PJ_SUCCESS;
- }
diff --git a/package/pjsip/patches/210-pjmedia_audiodev.patch b/package/pjsip/patches/210-pjmedia_audiodev.patch
deleted file mode 100644
index bb2a22183d..0000000000
--- a/package/pjsip/patches/210-pjmedia_audiodev.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/pjmedia/src/pjmedia-audiodev/audiodev.c
-+++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
-@@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_md
- pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
- #endif
- 
-+#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
-+pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf);
-+#endif
-+
- #define MAX_DRIVERS	16
- #define MAX_DEVS	64
- 
-@@ -409,6 +413,9 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_i
- #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
-     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
- #endif
-+#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
-+    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_tapi_factory;
-+#endif
- 
-     /* Initialize each factory and build the device ID list */
-     for (i=0; i<aud_subsys.drv_cnt; ++i) {
diff --git a/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c
deleted file mode 100644
index e6d531a538..0000000000
--- a/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c
+++ /dev/null
@@ -1,1017 +0,0 @@
-/******************************************************************************
-
-                               Copyright (c) 2010
-                            Lantiq Deutschland GmbH
-                     Am Campeon 3; 85579 Neubiberg, Germany
-
-  For licensing information, see the file 'LICENSE' in the root folder of
-  this software module.
-
-******************************************************************************/
-#include <pjmedia-audiodev/audiodev_imp.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/os.h>
-
-/* Linux includes */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <sys/stat.h> 
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <poll.h>
-
-#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
-/* TAPI includes */
-#include "drv_tapi_io.h"
-#include "vmmc_io.h"
-
-/* Maximum 2 devices */
-#define TAPI_AUDIO_PORT_NUM          (2)
-#define TAPI_BASE_NAME              "TAPI"
-#define TAPI_LL_DEV_BASE_PATH       "/dev/vmmc"
-#define TAPI_LL_DEV_FIRMWARE_NAME   "/lib/firmware/danube_firmware.bin"
-#define TAPI_LL_BBD_NAME   "/lib/firmware/danube_bbd_fxs.bin"
-
-#define TAPI_LL_DEV_SELECT_TIMEOUT_MS      (2000)
-#define TAPI_LL_DEV_MAX_PACKET_SIZE        (800)
-#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE   (12)
-#define TAPI_LL_DEV_ENC_FRAME_LEN_MS       (20)
-#define TAPI_LL_DEV_ENC_SMPL_PER_SEC       (8000)
-#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS     (16)
-#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME     (160)
-#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME    (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
-
-#define THIS_FILE     "tapi_dev.c"
-
-#if 1
-#   define TRACE_(x)    PJ_LOG(1,x)
-#else
-#   define TRACE_(x)
-#endif
-
-pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
-
-typedef struct
-{
-	pj_int32_t dev_fd;
-	pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
-	pj_int8_t  data2phone_map[TAPI_AUDIO_PORT_NUM];
-} tapi_ctx;
-
-struct tapi_aud_factory
-{
-	pjmedia_aud_dev_factory	base;
-	pj_pool_t		*pool;
-	pj_pool_factory		*pf;
-	pj_uint32_t		dev_count;
-	pjmedia_aud_dev_info	*dev_info;
-	tapi_ctx		dev_ctx;
-};
-
-typedef struct tapi_aud_factory tapi_aud_factory_t;
-
-struct tapi_aud_stream
-{
-	pjmedia_aud_stream	base;
-	pj_pool_t		*pool;
-	pjmedia_aud_param	param;
-	pjmedia_aud_rec_cb	rec_cb;
-	pjmedia_aud_play_cb	play_cb;
-	void			*user_data;
-
-	pj_thread_desc		thread_desc;
-	pj_thread_t		*thread;
-	tapi_ctx		*dev_ctx;
-	pj_uint8_t		run_flag;
-	pj_timestamp		timestamp;
-};
-
-typedef struct tapi_aud_stream tapi_aud_stream_t;
-
-/* Factory prototypes */
-static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
-static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
-static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
-static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
-          unsigned index,
-          pjmedia_aud_dev_info *info);
-static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
-           unsigned index,
-           pjmedia_aud_param *param);
-static pj_status_t 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_aud_strm);
-
-/* Stream prototypes */
-static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
-          pjmedia_aud_param *param);
-static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
-              pjmedia_aud_dev_cap cap,
-              void *value);
-static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
-              pjmedia_aud_dev_cap cap,
-              const void *value);
-static pj_status_t stream_start(pjmedia_aud_stream *strm);
-static pj_status_t stream_stop(pjmedia_aud_stream *strm);
-static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
-
-static pjmedia_aud_dev_factory_op tapi_fact_op =
-{
-	&factory_init,
-	&factory_destroy,
-	&factory_get_dev_count,
-	&factory_get_dev_info,
-	&factory_default_param,
-	&factory_create_stream
-};
-
-static pjmedia_aud_stream_op tapi_strm_op =
-{
-	&stream_get_param,
-	&stream_get_cap,
-	&stream_set_cap,
-	&stream_start,
-	&stream_stop,
-	&stream_destroy
-};
-
-void (*tapi_digit_callback)(unsigned int port, unsigned char digit) = NULL;
-void (*tapi_hook_callback)(unsigned int port, unsigned char event) = NULL;
-
-static pj_int32_t
-tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
-{
-	char devname[128] = {0};
-	pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
-	return open((const char*)devname, O_RDWR, 0644);
-}
-
-static pj_status_t
-tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
-{
-	pj_status_t status = PJ_SUCCESS;
-	FILE *fd;
-	struct stat file_stat;
-
-	fd = fopen(pPath, "rb");
-	if (fd == NULL) {
-		TRACE_((THIS_FILE, "ERROR -  binary file %s open failed!\n", pPath));
-		return PJ_EUNKNOWN;
-	}
-
-	if (stat(pPath, &file_stat) != 0) {
-		TRACE_((THIS_FILE, "ERROR -  file %s statistics get failed!\n", pPath));
-		return PJ_EUNKNOWN;
-	}
-
-	*ppBuf = malloc(file_stat.st_size);
-	if (*ppBuf == NULL) {
-		TRACE_((THIS_FILE, "ERROR -  binary file %s memory allocation failed!\n", pPath));
-		status = PJ_EUNKNOWN;
-		goto on_exit;
-	}
-
-	if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
-		TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
-		status = PJ_EUNKNOWN;
-		goto on_exit;
-	}
-
-	*pBufSz = file_stat.st_size;
-
-on_exit:
-	if (fd != NULL)
-		fclose(fd);
-
-	if (*ppBuf != NULL && status != PJ_SUCCESS)
-		free(*ppBuf);
-
-	return status;
-}
-
-static void
-tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
-{
-	if (pBuf != NULL)
-		free(pBuf);
-}
-
-static pj_status_t
-tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
-{
-	pj_status_t status = PJ_SUCCESS;
-	pj_uint8_t *pFirmware = NULL;
-	pj_uint32_t binSz = 0;
-	VMMC_IO_INIT vmmc_io_init;
-
-	status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
-		return PJ_EUNKNOWN;
-	}
-
-	memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
-	vmmc_io_init.pPRAMfw   = pFirmware;
-	vmmc_io_init.pram_size = binSz;
-
-	status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
-	if (status != PJ_SUCCESS)
-		TRACE_((THIS_FILE, "ERROR -  FIO_FW_DOWNLOAD ioctl failed!"));
-
-	tapi_dev_binary_buffer_delete(pFirmware);
-
-	return status;
-}
-
-static int
-tapi_dev_bbd_download(int fd, const char *pPath)
-{
-	int status = PJ_SUCCESS;
-	unsigned char *pFirmware = NULL;
-	unsigned int binSz = 0;
-	VMMC_DWLD_t bbd_data;
-
-
-	/* Create binary buffer */
-	status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
-		return status;
-	}
-
-	/* Download Voice Firmware */
-	memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
-	bbd_data.buf = pFirmware;
-	bbd_data.size = binSz;
-
-	status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
-	}
-
-	/* Delete binary buffer */
-	tapi_dev_binary_buffer_delete(pFirmware);
-
-	return status;
-}
-
-static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
-{
-	pj_uint8_t c, hook_status;
-	pj_status_t status = PJ_SUCCESS;
-	IFX_TAPI_DEV_START_CFG_t tapistart;
-	IFX_TAPI_MAP_DATA_t datamap;
-	IFX_TAPI_ENC_CFG_t enc_cfg;
-	IFX_TAPI_LINE_VOLUME_t line_vol;
-	IFX_TAPI_CID_CFG_t cid_cnf;
-	
-	/* Open device */
-	f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
-	
-	if (f->dev_ctx.dev_fd < 0) {
-		TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
-		ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
-
-		if (f->dev_ctx.dev_fd < 0) {
-			TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
-			return PJ_EUNKNOWN;
-		}
-		f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
-	}
-
-	status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	/* Download coefficients */
-	/*
-	status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
-		return PJ_EUNKNOWN;
-	}
-	*/
-
-	memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
-	tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
-	
-	/* Start TAPI */
-	status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
-	if (status != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
-		return PJ_EUNKNOWN;
-	}
-
-
-	for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
-		/* Perform mapping */
-		memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
-		datamap.nDstCh  = f->dev_ctx.data2phone_map[c];
-		datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
-		
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
-		
-		if (status != PJ_SUCCESS) {
-			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
-			return PJ_EUNKNOWN;
-		}
-		
-		/* Set Line feed */
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
-		
-		if (status != PJ_SUCCESS) {
-			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
-			return PJ_EUNKNOWN;
-		}
-		
-		/* Configure encoder for linear stream */
-		memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
-		
-		enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
-		enc_cfg.nEncType  = IFX_TAPI_COD_TYPE_LIN16_8;
-		
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
-		if (status != PJ_SUCCESS) {
-			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
-			return PJ_EUNKNOWN;
-		}
-		
-		/* Suppress TAPI volume, otherwise PJSIP starts autogeneration!!! */
-		line_vol.nGainRx = -8;
-		line_vol.nGainTx = -8;
-		
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
-		if (status != PJ_SUCCESS) {
-			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
-			return PJ_EUNKNOWN;
-		}
-		
-		/* Configure Caller ID type */
-		/* One can choose from following (for now at compile time):
-			IFX_TAPI_CID_STD_TELCORDIA
-			IFX_TAPI_CID_STD_ETSI_FSK
-			IFX_TAPI_CID_STD_ETSI_DTMF
-			IFX_TAPI_CID_STD_SIN
-			IFX_TAPI_CID_STD_NTT
-			IFX_TAPI_CID_STD_KPN_DTMF
-			IFX_TAPI_CID_STD_KPN_DTMF_FSK
-		*/
-		memset(&cid_cnf, 0, sizeof(cid_cnf));
-		cid_cnf.nStandard = IFX_TAPI_CID_STD_ETSI_FSK;
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cnf);
-		if (status != PJ_SUCCESS) {
-			TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
-			return PJ_EUNKNOWN;
-		}
-		
-		/* check hook status */
-		hook_status = 0;
-		status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
-		if (status != PJ_SUCCESS) {
-		   TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
-		   return PJ_EUNKNOWN;
-		}
-		
-		/* if off hook do initialization */
-		if (hook_status) {
-			status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
-			if (status != PJ_SUCCESS) {
-				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
-				return PJ_EUNKNOWN;
-			}
-			status = ioctl(c, IFX_TAPI_ENC_START, 0);
-			if (status != PJ_SUCCESS) {
-				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
-				return PJ_EUNKNOWN;
-			}
-
-			status = ioctl(c, IFX_TAPI_DEC_START, 0);
-			if (status != PJ_SUCCESS) {
-				TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
-				return PJ_EUNKNOWN;
-			}
-		}
-	}
-
-	return status;
-}
-
-static pj_status_t
-tapi_dev_stop(tapi_aud_factory_t *f)
-{
-	pj_status_t status = PJ_SUCCESS;
-	pj_uint8_t c;
-
-	if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
-		status = PJ_EUNKNOWN;
-	}
-
-	close(f->dev_ctx.dev_fd);
-	for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
-		close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
-
-	return status;
-}
-
-static pj_status_t
-tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
-{
-	if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
-			start ? "START" : "STOP"));
-		return PJ_EUNKNOWN;
-	}
-
-	if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
-			start ? "START" : "STOP"));
-		return PJ_EUNKNOWN;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
-{
-   PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
-
-   if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
-               IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
-
-      return PJ_EUNKNOWN;
-   }
-
-   /* enc/dec stop */
-   if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - codec start failed!"));
-
-      return PJ_EUNKNOWN;
-   }
-
-   return PJ_SUCCESS;
-}
-
-static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
-{
-   PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
-
-   if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
-               IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
-
-      return PJ_EUNKNOWN;
-   }
-
-   /* enc/dec stop */
-   if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - codec start failed!"));
-
-      return PJ_EUNKNOWN;
-   }
-
-   return PJ_SUCCESS;
-}
-
-static pj_status_t
-tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
-{
-	PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
-
-	if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
-			IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	/* enc/dec stop */
-	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-tapi_dev_event_handler(tapi_aud_stream_t *stream)
-{
-	IFX_TAPI_EVENT_t tapiEvent;
-	tapi_ctx *dev_ctx = stream->dev_ctx;
-	pj_status_t status = PJ_SUCCESS;
-	unsigned int i;
-
-	for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
-		memset (&tapiEvent, 0, sizeof(tapiEvent));
-		tapiEvent.ch = dev_ctx->data2phone_map[i];
-		status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
-
-		if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
-			switch(tapiEvent.id) {
-			case IFX_TAPI_EVENT_FXS_ONHOOK:
-				status = tapi_dev_event_on_hook(dev_ctx, i);
-				if(tapi_hook_callback)
-					tapi_hook_callback(i, 0);
-				break;
-			case IFX_TAPI_EVENT_FXS_OFFHOOK:
-				status = tapi_dev_event_off_hook(dev_ctx, i);
-				if(tapi_hook_callback)
-					tapi_hook_callback(i, 1);
-				break;
-			case IFX_TAPI_EVENT_DTMF_DIGIT:
-				if(tapi_digit_callback)
-					tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
-				break;
-			case IFX_TAPI_EVENT_COD_DEC_CHG:
-			case IFX_TAPI_EVENT_TONE_GEN_END:
-			case IFX_TAPI_EVENT_CID_TX_SEQ_END:
-				break;
-			default:
-				PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
-				break;
-			}
-		}
-	}
-
-	return status;
-}
-
-static pj_status_t
-tapi_dev_data_handler(tapi_aud_stream_t *stream) {
-   pj_status_t status = PJ_SUCCESS;
-   tapi_ctx *dev_ctx = stream->dev_ctx;
-   pj_uint32_t dev_idx = stream->param.rec_id;
-   pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
-   pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
-   pjmedia_frame frame_rec, frame_play;
-   pj_int32_t ret;
-
-   /* Get data from driver */
-   ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
-   if (ret < 0) {
-      TRACE_((THIS_FILE, "ERROR - no data available from device!"));
-
-      return PJ_EUNKNOWN;
-   }
-
-   if (ret > 0) {
-      frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
-      frame_rec.buf  = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
-      frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
-      frame_rec.timestamp.u64 = stream->timestamp.u64;
-
-      status = stream->rec_cb(stream->user_data, &frame_rec);
-      if (status != PJ_SUCCESS)
-      {
-        PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
-      }
-
-      frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
-      frame_play.buf  = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
-      frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
-      frame_play.timestamp.u64 = stream->timestamp.u64;
-
-      status = (*stream->play_cb)(stream->user_data, &frame_play);
-      if (status != PJ_SUCCESS)
-      {
-         PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
-      }
-      else
-      {
-         memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
-
-         ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
-
-         if (ret < 0) {
-            PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
-            return PJ_EUNKNOWN;
-         }
-
-         if (ret == 0) {
-            PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
-            return PJ_EUNKNOWN;
-         }
-      }
-
-      stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
-   }
-
-   return PJ_SUCCESS;
-}
-
-static int
-PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
-	tapi_aud_stream_t *strm = (struct tapi_aud_stream*)arg;
-	tapi_ctx *dev_ctx = strm->dev_ctx;
-	pj_uint32_t sretval;
-	pj_uint32_t dev_idx;
-	struct pollfd fds[3];
-
-	PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
-
-	if (strm->param.rec_id != strm->param.play_id) {
-		PJ_LOG(1,(THIS_FILE, "TAPI: thread exit - incorrect play/rec IDs"));
-		return 0;
-	}
-
-	dev_idx = strm->param.rec_id;
-	strm->run_flag = 1;
-
-	fds[0].fd = dev_ctx->dev_fd;
-	fds[0].events = POLLIN;
-	fds[1].fd = dev_ctx->ch_fd[0];
-	fds[1].events = POLLIN;
-	fds[2].fd = dev_ctx->ch_fd[1];
-	fds[2].events = POLLIN;
-
-	while(1)
-	{
-		sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
-
-		if (!strm->run_flag)
-			break;
-		if (sretval <= 0)
-			continue;
-
-		if (fds[0].revents == POLLIN) {
-			if (tapi_dev_event_handler(strm) != PJ_SUCCESS) {
-				PJ_LOG(1,(THIS_FILE, "TAPI: event hanldler failed!"));
-				break;
-			}
-		}
-
-		if (fds[1].revents == POLLIN) {
-			if (tapi_dev_data_handler(strm) != PJ_SUCCESS) {
-				PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!"));
-				break;
-			}
-		}
-
-		if (fds[2].revents == POLLIN) {
-			if (tapi_dev_data_handler(strm) != PJ_SUCCESS) {
-				PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!"));
-				break;
-			}
-		}
-	}
-	PJ_LOG(1,(THIS_FILE, "TAPI: thread stopping..."));
-
-	return 0;
-}
-
-/****************************************************************************
- Factory operations
- ****************************************************************************/
-
-pjmedia_aud_dev_factory*
-pjmedia_tapi_factory(pj_pool_factory *pf) {
-	struct tapi_aud_factory *f;
-	pj_pool_t *pool;
-
-	TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
-
-	pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
-	f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
-	f->pf = pf;
-	f->pool = pool;
-	f->base.op = &tapi_fact_op;
-
-	return &f->base;
-}
-
-static pj_status_t
-factory_init(pjmedia_aud_dev_factory *f)
-{
-	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-	pj_uint8_t c;
-
-	TRACE_((THIS_FILE, "factory_init()"));
-
-	af->dev_count = 1;
-	af->dev_info = (pjmedia_aud_dev_info*)
-	pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
-	pj_ansi_sprintf(af->dev_info[0].name,"%s_%02d", TAPI_BASE_NAME, c);
-	af->dev_info[0].input_count = af->dev_info[0].output_count = TAPI_AUDIO_PORT_NUM;
-	af->dev_info[0].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
-	pj_ansi_strcpy(af->dev_info[0].driver, "/dev/vmmc");
-	af->dev_info[0].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
-		PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
-		PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
-	af->dev_info[0].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
-	if (tapi_dev_start(af) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-factory_destroy(pjmedia_aud_dev_factory *f)
-{
-	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-	pj_pool_t *pool;
-	pj_status_t status = PJ_SUCCESS;
-
-	TRACE_((THIS_FILE, "factory_destroy()"));
-
-	if (tapi_dev_stop(f) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
-		status = PJ_EUNKNOWN;
-	}
-	pool = af->pool;
-	af->pool = NULL;
-	pj_pool_release(pool);
-
-	return status;
-}
-
-static unsigned
-factory_get_dev_count(pjmedia_aud_dev_factory *f)
-{
-	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-	TRACE_((THIS_FILE, "factory_get_dev_count()"));
-
-	return af->dev_count;
-}
-
-static pj_status_t
-factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
-{
-	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-
-	TRACE_((THIS_FILE, "factory_get_dev_info()"));
-	PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
-
-	pj_memcpy(info, &af->dev_info[index], sizeof(*info));
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
-{
-	struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-	struct pjmedia_aud_dev_info *di = &af->dev_info[index];
-
-	TRACE_((THIS_FILE, "factory_default_param."));
-	PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
-
-	pj_bzero(param, sizeof(*param));
-	if (di->input_count && di->output_count) {
-		param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-		param->rec_id = index;
-		param->play_id = index;
-	} else if (di->input_count) {
-		param->dir = PJMEDIA_DIR_CAPTURE;
-		param->rec_id = index;
-		param->play_id = PJMEDIA_AUD_INVALID_DEV;
-	} else if (di->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 = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
-	param->channel_count = 1;
-	param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
-	param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
-	param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
-	param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-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_aud_strm)
-{
-   struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
-   pj_pool_t *pool;
-   struct tapi_aud_stream *strm;
-   pj_status_t status;
-
-   TRACE_((THIS_FILE, "factory_create_stream()"));
-
-   /* Can only support 16bits per sample */
-   PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
-   printf("param->clock_rate = %d, samples_per_frame = %d\n", param->clock_rate, param->samples_per_frame);
-   PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
-
-   PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
-
-   /* Can only support bidirectional stream */
-   PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
-
-   /* Initialize our stream data */
-   pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
-   PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
-
-   strm = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_stream);
-   strm->pool      = pool;
-   strm->rec_cb    = rec_cb;
-   strm->play_cb   = play_cb;
-   strm->user_data = user_data;
-   pj_memcpy(&strm->param, param, sizeof(*param));
-
-   if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
-      strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
-   }
-
-   strm->timestamp.u64 = 0;
-   strm->dev_ctx = &(af->dev_ctx);
-
-   /* Create and start the thread */
-   status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, 
-			      &strm->thread);
-   if (status != PJ_SUCCESS) {
-      stream_destroy(&strm->base);
-      return status;
-   }
-
-   /* Done */
-   strm->base.op = &tapi_strm_op;
-   *p_aud_strm = &strm->base;
-
-   return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
-{
-	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
-
-	PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-	pj_memcpy(pi, &strm->param, sizeof(*pi));
-
-	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
-			&pi->output_vol) == PJ_SUCCESS)
-		pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
-
-	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
-			&pi->output_latency_ms) == PJ_SUCCESS)
-		pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
-
-	if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
-			&pi->input_latency_ms) == PJ_SUCCESS)
-		pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
-{
-	// struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
-{
-	// struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_start(pjmedia_aud_stream *s)
-{
-	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
-	tapi_ctx *dev_ctx = strm->dev_ctx;
-	pj_uint32_t dev_idx;
-
-	TRACE_((THIS_FILE, "stream_start()"));
-
-	dev_idx = strm->param.rec_id;
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_stop(pjmedia_aud_stream *s)
-{
-	struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
-	tapi_ctx *dev_ctx = strm->dev_ctx;
-	pj_uint32_t dev_idx;
-
-	TRACE_((THIS_FILE, "stream_stop()"));
-	dev_idx = strm->param.rec_id;
-
-	if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - codec start failed!"));
-		return PJ_EUNKNOWN;
-	}
-
-	return PJ_SUCCESS;
-}
-
-static pj_status_t
-stream_destroy(pjmedia_aud_stream *s)
-{
-	pj_status_t state = PJ_SUCCESS;
-	struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
-	pj_pool_t *pool;
-
-	PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-	TRACE_((THIS_FILE, "stream_destroy()"));
-
-	stream_stop(stream);
-	stream->run_flag = 0;
-
-	if (stream->thread)
-	{
-		pj_thread_join(stream->thread);
-		pj_thread_destroy(stream->thread);
-		stream->thread = NULL;
-	}
-
-	pool = stream->pool;
-	pj_bzero(stream, sizeof(stream));
-	pj_pool_release(pool);
-
-	return state;
-}
-
-pj_status_t
-tapi_hook_status(pj_uint32_t port, pj_uint32_t *status)
-{
-	if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
-			!= PJ_SUCCESS) {
-		TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
-		return PJ_EUNKNOWN;
-	}
-		
-	return PJ_SUCCESS;
-}
-
-pj_status_t
-tapi_ring(pj_uint32_t port, pj_uint32_t state, char *caller_number) {
-	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
-
-	if (state) {
-		if (caller_number) {
-			IFX_TAPI_CID_MSG_t cid_msg;
-			IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
-			memset(&cid_msg, 0, sizeof(cid_msg));
-			memset(&cid_msg_el, 0, sizeof(cid_msg_el));
-
-			cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
-			cid_msg_el[0].string.len = strlen(caller_number);
-			strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
-
-			cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
-			cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
-			cid_msg.nMsgElements = 1;
-			cid_msg.message = cid_msg_el;
-			ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
-		} else {
-			ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
-		}
-	} else {
-		ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
-	}
-
-	return PJ_SUCCESS;
-}
-
-pj_status_t
-tapi_dial_tone(pj_uint32_t port) {
-	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
-
-	ioctl(ch_fd[port], IFX_TAPI_TONE_DIALTONE_PLAY, 0);
-
-	return PJ_SUCCESS;
-}
-
-pj_status_t
-tapi_no_tone(pj_uint32_t port) {
-	PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
-
-	ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
-
-	return PJ_SUCCESS;
-}
-
-#endif