summaryrefslogtreecommitdiff
path: root/package/pjsip/patches
diff options
context:
space:
mode:
Diffstat (limited to 'package/pjsip/patches')
-rw-r--r--package/pjsip/patches/0001-configure-fixup.patch78
-rw-r--r--package/pjsip/patches/0002-register-tapi.patch1333
-rw-r--r--package/pjsip/patches/0003-adds-PJ_DEF-pj_status_t-pjsua_add_snd_port-int-id.patch207
3 files changed, 0 insertions, 1618 deletions
diff --git a/package/pjsip/patches/0001-configure-fixup.patch b/package/pjsip/patches/0001-configure-fixup.patch
deleted file mode 100644
index 5fcf911c3b..0000000000
--- a/package/pjsip/patches/0001-configure-fixup.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-Index: pjproject-1.14.2/aconfigure.ac
-===================================================================
---- pjproject-1.14.2.orig/aconfigure.ac 2012-04-27 03:22:15.000000000 +0200
-+++ pjproject-1.14.2/aconfigure.ac 2012-08-13 14:42:33.204641678 +0200
-@@ -48,9 +48,8 @@
- CROSS_COMPILE=`echo ${CC} | sed 's/gcc//'`
- fi
-
--if test "$AR" = ""; then AR="${CROSS_COMPILE}ar rv"; fi
-+AR="${AR} rv"
- AC_SUBST(AR)
--if test "$LD" = ""; then LD="$CC"; fi
- AC_SUBST(LD)
- if test "$LDOUT" = ""; then LDOUT="-o "; fi
- AC_SUBST(LDOUT)
-@@ -584,13 +583,7 @@
- ;;
- *)
- dnl # Check if ALSA is available
-- ac_pjmedia_snd=pa_unix
-- AC_CHECK_HEADER(alsa/version.h,
-- [AC_SUBST(ac_pa_use_alsa,1)
-- LIBS="$LIBS -lasound"
-- ],
-- [AC_SUBST(ac_pa_use_alsa,0)])
-- AC_MSG_RESULT([Checking sound device backend... unix])
-+ AC_SUBST(ac_pa_use_alsa,0)
-
- dnl # Check if OSS is disabled
- AC_SUBST(ac_pa_use_oss,1)
-@@ -617,6 +610,15 @@
- 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,
-@@ -737,14 +739,6 @@
- AC_MSG_RESULT([Checking if iLBC codec is disabled...no]))
-
- dnl # Include libsamplerate
--AC_ARG_ENABLE(libsamplerate,
-- AC_HELP_STRING([--enable-libsamplerate],
-- [Link with libsamplerate when available. Note that PJMEDIA_RESAMPLE_IMP must also be configured]),
-- [ AC_CHECK_LIB(samplerate,src_new) ],
-- AC_MSG_RESULT([Skipping libsamplerate detection])
-- )
--
--dnl # Include libsamplerate
- AC_SUBST(ac_resample_dll)
- AC_ARG_ENABLE(resample_dll,
- AC_HELP_STRING([--enable-resample-dll],
-Index: pjproject-1.14.2/pjmedia/build/os-auto.mak.in
-===================================================================
---- pjproject-1.14.2.orig/pjmedia/build/os-auto.mak.in 2011-10-14 06:15:15.000000000 +0200
-+++ pjproject-1.14.2/pjmedia/build/os-auto.mak.in 2012-08-13 14:40:47.680637171 +0200
-@@ -125,4 +125,11 @@
- 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/0002-register-tapi.patch b/package/pjsip/patches/0002-register-tapi.patch
deleted file mode 100644
index 4363bc7ff8..0000000000
--- a/package/pjsip/patches/0002-register-tapi.patch
+++ /dev/null
@@ -1,1333 +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) {
---- /dev/null
-+++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
-@@ -0,0 +1,1307 @@
-+/******************************************************************************
-+
-+ 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_PULSE_DIGIT:
-+ if(tapi_digit_callback)
-+ if(tapiEvent.data.pulse.digit == 0xB)
-+ tapi_digit_callback(i, '0');
-+ else
-+ tapi_digit_callback(i, '0' + tapiEvent.data.pulse.digit);
-+ 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 */
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
deleted file mode 100644
index 3331c84828..0000000000
--- a/package/pjsip/patches/0003-adds-PJ_DEF-pj_status_t-pjsua_add_snd_port-int-id.patch
+++ /dev/null
@@ -1,207 +0,0 @@
---- a/pjsip/include/pjsua-lib/pjsua.h
-+++ b/pjsip/include/pjsua-lib/pjsua.h
-@@ -1543,6 +1543,8 @@ PJ_DECL(pjmedia_endpt*) pjsua_get_pjmedi
- 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.
---- 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. */
---- 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 &&
-@@ -2008,7 +2008,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect(
- 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
-@@ -2072,7 +2072,7 @@ PJ_DEF(pj_status_t) pjsua_conf_connect(
- /* 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;
-@@ -2686,9 +2686,9 @@ static pj_status_t update_initial_aud_pa
- 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) {
-@@ -2754,7 +2754,7 @@ static pj_status_t open_snd_dev(pjmedia_
- 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;
-
-@@ -2812,13 +2812,13 @@ static pj_status_t open_snd_dev(pjmedia_
- }
-
- /* 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;
- }
-
-@@ -2833,7 +2833,7 @@ static pj_status_t open_snd_dev(pjmedia_
- 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);
-@@ -2876,12 +2876,12 @@ static pj_status_t open_snd_dev(pjmedia_
- 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)
-@@ -2893,9 +2893,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 */
-@@ -2984,6 +2984,35 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( i
- 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
-@@ -3088,7 +3117,7 @@ PJ_DEF(pj_status_t) pjsua_set_ec(unsigne
- pjsua_var.media_cfg.ec_options = options;
-
- if (pjsua_var.snd_port)
-- status = pjmedia_snd_port_set_ec(pjsua_var.snd_port, pjsua_var.pool,
-+ status = pjmedia_snd_port_set_ec(pjsua_var.snd_port[0], pjsua_var.pool,
- tail_ms, options);
-
- PJSUA_UNLOCK();
-@@ -3111,7 +3140,7 @@ PJ_DEF(pj_status_t) pjsua_get_ec_tail(un
- */
- PJ_DEF(pj_bool_t) pjsua_snd_is_active(void)
- {
-- return pjsua_var.snd_port != NULL;
-+ return pjsua_var.snd_port[0] != NULL;
- }
-
-
-@@ -3135,7 +3164,7 @@ PJ_DEF(pj_status_t) pjsua_snd_set_settin
- 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;
-@@ -3181,7 +3210,7 @@ PJ_DEF(pj_status_t) pjsua_snd_get_settin
- /* 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]);
- status = pjmedia_aud_stream_get_cap(strm, cap, pval);
- } else {
- /* Otherwise retrieve from internal param */