pjsip: bump to 1.10 and improve ltq_tapi backend
authorJohn Crispin <john@openwrt.org>
Fri, 11 Nov 2011 22:23:26 +0000 (22:23 +0000)
committerJohn Crispin <john@openwrt.org>
Fri, 11 Nov 2011 22:23:26 +0000 (22:23 +0000)
SVN-Revision: 28963

package/pjsip/Makefile
package/pjsip/patches/000-aconf.patch
package/pjsip/patches/100-pjsua_acc__snprintf.patch
package/pjsip/patches/210-pjmedia_audiodev.patch
package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c

index 42db149baf3f313732af546c6512b6da7dd6ea17..b7628089e27db550dbcf2916a8fe875b6223553a 100644 (file)
@@ -8,13 +8,15 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=pjsip
-PKG_VERSION:=1.8.5
-PKG_RELEASE:=2
+PKG_VERSION:=1.10
+PKG_RELEASE:=3
 
 PKG_SOURCE:=pjproject-$(PKG_VERSION).tar.bz2
 PKG_SOURCE_URL:=http://www.pjsip.org/release/$(PKG_VERSION)/
-PKG_MD5SUM:=f9aa9e58b4d697245eb4bfa7d81a54a3
+PKG_MD5SUM:=e215d0637d3422d49a63c2cde6673951
+
 PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/pjproject-$(PKG_VERSION)
 
@@ -36,6 +38,7 @@ CONFIGURE_PREFIX=/usr/pjsip-$(BUILD_VARIANT)
 
 ifeq ($(BUILD_VARIANT),oss)
 CONFIGURE_ARGS += \
+       --disable-floating-point \
        --enable-g711-codec \
        --disable-l16-codec \
        --disable-g722-codec \
@@ -51,6 +54,7 @@ endif
 
 ifeq ($(BUILD_VARIANT),ltq-tapi)
 CONFIGURE_ARGS += \
+       --disable-floating-point \
        --enable-g711-codec \
        --disable-l16-codec \
        --disable-g722-codec \
@@ -80,15 +84,15 @@ define Build/Configure
 endef
 
 define Build/Compile
-       CFLAGS="$(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
-       LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS) $(LIBGCC_S)" \
-               $(MAKE) -C $(PKG_BUILD_DIR)/$(MAKE_PATH)
+       CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+       CXXFLAGS="$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS)" \
+       LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS) $(LIBGCC_S) -lm" \
+               $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)/$(MAKE_PATH)
 endef
 
 define Build/InstallDev
-       $(INSTALL_DIR) $(1)/usr/
-       $(CP) $(PKG_INSTALL_DIR)/usr/pjsip-$(BUILD_VARIANT) \
-               $(1)/usr/
+       $(INSTALL_DIR) $(1)/usr
+       $(CP) $(PKG_INSTALL_DIR)/usr/pjsip-$(BUILD_VARIANT) $(1)/usr
 endef
 
 define Package/pjsip-$(BUILD_VARIANT)/install
index 96c519aea0cd013615a56e4a2655bebc477fb8bc..46e4aad4ac33a951adab94590c7e1bf9bc1c4f0a 100644 (file)
@@ -1,15 +1,18 @@
 --- a/aconfigure.ac
 +++ b/aconfigure.ac
-@@ -48,7 +48,7 @@
+@@ -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
+-if test "$LD" = ""; then LD="$CC"; fi
++LD="${CROSS_COMPILE}gcc"
  AC_SUBST(LD)
-@@ -590,6 +590,15 @@
+ 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]
              )
@@ -27,7 +30,7 @@
  AC_SUBST(ac_no_small_filter)
 --- a/pjmedia/build/os-auto.mak.in
 +++ b/pjmedia/build/os-auto.mak.in
-@@ -118,4 +118,11 @@
+@@ -118,4 +118,11 @@ ifeq ($(AC_PJMEDIA_SND),external)
  export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
  endif
  
index cb347213d61a1bb3a8facc809d52c437b28e3759..929ecc94dd7a8097db81cb1ee38dd1238a9f6606 100644 (file)
@@ -1,6 +1,6 @@
 --- a/pjsip/src/pjsua-lib/pjsua_acc.c
 +++ b/pjsip/src/pjsua-lib/pjsua_acc.c
-@@ -430,7 +430,7 @@
+@@ -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,
@@ -9,9 +9,9 @@
                     endquote,
                     t->local_name.port,
                     transport_param);
-@@ -1158,18 +1158,18 @@
+@@ -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",
+                              "<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 : "",
                               (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);
-@@ -2233,22 +2233,22 @@
+@@ -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%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 : "",
                                     (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;
  }
-@@ -2390,22 +2390,22 @@
+@@ -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,
index 8acba6ef45bb33362fc0523292e105ad860134cd..bb2a22183d38fdc38c0fcb5e110f1f9712462883 100644 (file)
@@ -1,6 +1,6 @@
 --- a/pjmedia/src/pjmedia-audiodev/audiodev.c
 +++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
-@@ -98,6 +98,10 @@
+@@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_md
  pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
  #endif
  
@@ -11,7 +11,7 @@
  #define MAX_DRIVERS   16
  #define MAX_DEVS      64
  
-@@ -404,6 +408,9 @@
+@@ -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
index a367df30fd819b1478294f413ddf3affbab8d47e..e6d531a53881b211b11ed679277cbf05af56f6a3 100644 (file)
@@ -15,7 +15,7 @@
 #include <pj/log.h>
 #include <pj/os.h>
 
-/* Linux includes*/
+/* Linux includes */
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <unistd.h>
+#include <poll.h>
 
 #if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
-
-/* TAPI includes*/
+/* TAPI includes */
 #include "drv_tapi_io.h"
 #include "vmmc_io.h"
 
-/* Maximum 2 devices*/
-#define TAPI_AUDIO_DEV_NUM          (1)
-#define TAPI_AUDIO_MAX_DEV_NUM      (2)
+/* 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_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)
@@ -50,9 +50,6 @@
 #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 FD_WIDTH_SET(fd, maxfd)   (maxfd) < (fd) ? (fd) : maxfd 
-
 #define THIS_FILE     "tapi_dev.c"
 
 #if 1
 #   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_DEV_NUM];
-   pj_int8_t  data2phone_map[TAPI_AUDIO_DEV_NUM];
-   
+       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;
 
-
-/* TAPI factory */
 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;
+       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;
 
-/*
-   Sound stream descriptor.
-**/
 struct tapi_aud_stream
 {
-   /* Base*/
-   pjmedia_aud_stream   base;      /**< Base class.  */
-   /* Pool*/
-   pj_pool_t            *pool;     /**< Memory pool.       */
-   /* Common settings.*/
-   pjmedia_aud_param    param;     /**< Stream param.  */
-   pjmedia_aud_rec_cb   rec_cb;    /**< Record callback.   */
-   pjmedia_aud_play_cb  play_cb;   /**< Playback callback. */
-   void                *user_data; /**< Application data.  */
-
-   pj_thread_desc       thread_desc;
-   pj_thread_t         *thread;
-   tapi_ctx            *dev_ctx;
-   pj_uint8_t           run_flag;
-   pj_timestamp         timestamp;
+       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;
@@ -140,265 +128,329 @@ 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
-  };
+{
+       &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
+       &stream_get_param,
+       &stream_get_cap,
+       &stream_set_cap,
+       &stream_start,
+       &stream_stop,
+       &stream_destroy
 };
 
-void (*tapi_digit_callback)(unsigned char digit) = NULL;
-void (*tapi_hook_callback)(unsigned char event) = NULL;
+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)
+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);
+       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)
+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;
-
-   /* Open binary file for reading*/
-   fd = fopen(pPath, "rb");
-   if (fd == NULL) {
-      TRACE_((THIS_FILE, "ERROR -  binary file %s open failed!\n", pPath));
-      return PJ_EUNKNOWN;
-   }
-
-   /* Get file statistics*/
-   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; 
+       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 (fd != NULL)
+               fclose(fd);
 
-   if (*ppBuf != NULL && status != PJ_SUCCESS) {
-      free(*ppBuf);
-   }
+       if (*ppBuf != NULL && status != PJ_SUCCESS)
+               free(*ppBuf);
 
-   return status;
+       return status;
 }
 
-static void tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
+static void
+tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
 {
-   if (pBuf != NULL)
-      free(pBuf);
+       if (pBuf != NULL)
+               free(pBuf);
 }
 
-static pj_status_t tapi_dev_firmware_download(
-                     pj_int32_t fd,
-                     const char *pPath)
+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;
-
-   /* 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"));
+       pj_status_t status = PJ_SUCCESS;
+       pj_uint8_t *pFirmware = NULL;
+       pj_uint32_t binSz = 0;
+       VMMC_IO_INIT vmmc_io_init;
 
-      return PJ_EUNKNOWN;
-   }
+       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;
+       }
 
-   /* Download Voice Firmware*/
-   memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
-   vmmc_io_init.pPRAMfw   = pFirmware;
-   vmmc_io_init.pram_size = binSz;
+       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!"));
-   }
+       status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
+       if (status != PJ_SUCCESS)
+               TRACE_((THIS_FILE, "ERROR -  FIO_FW_DOWNLOAD ioctl failed!"));
 
-   /* Delete binary buffer*/
-   tapi_dev_binary_buffer_delete(pFirmware);
+       tapi_dev_binary_buffer_delete(pFirmware);
 
-   return status;
+       return status;
 }
 
-
-static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
+static int
+tapi_dev_bbd_download(int fd, const char *pPath)
 {
-   pj_status_t status = PJ_SUCCESS;
-   pj_uint8_t c;
-   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 vol;
-
-   /* 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_DEV_NUM; c++) {
-      f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_MAX_DEV_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;
-   }
-
-   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;
-   }
-
+       int status = PJ_SUCCESS;
+       unsigned char *pFirmware = NULL;
+       unsigned int binSz = 0;
+       VMMC_DWLD_t bbd_data;
 
-   for (c = 0; c < TAPI_AUDIO_DEV_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);
+       /* 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;
+       }
 
-      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);
+       /* Download Voice Firmware */
+       memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
+       bbd_data.buf = pFirmware;
+       bbd_data.size = binSz;
 
-      if (status != PJ_SUCCESS) {
-         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
-         return PJ_EUNKNOWN;
-      }
+       status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
+       if (status != PJ_SUCCESS) {
+               TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
+       }
 
-      /* Config encoder for linear stream*/
-      memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
+       /* Delete binary buffer */
+       tapi_dev_binary_buffer_delete(pFirmware);
 
-      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!!!*/
-      vol.nGainRx = -8;
-      vol.nGainTx = -8;
-
-      status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &vol);
-      if (status != PJ_SUCCESS) {
-         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
-         return PJ_EUNKNOWN;
-      }
-   }
-
-
-   return status;
+       return status;
 }
 
-static pj_status_t tapi_dev_stop(tapi_aud_factory_t *f)
+static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
 {
-   pj_status_t status = PJ_SUCCESS;
-   pj_uint8_t c;
-   
-   /* Stop TAPI device*/
-   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 device FD*/
-   close(f->dev_ctx.dev_fd);
-
-   /* Close channel FD*/
-   for (c = TAPI_AUDIO_DEV_NUM; c > 0; c--) {
-      close(f->dev_ctx.ch_fd[TAPI_AUDIO_DEV_NUM-c]);
-   }
-
-
-   return status;
+       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_codec_control(pj_int32_t fd, pj_uint8_t start)
+static pj_status_t
+tapi_dev_stop(tapi_aud_factory_t *f)
 {
-   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"));
+       pj_status_t status = PJ_SUCCESS;
+       pj_uint8_t c;
 
-      return PJ_EUNKNOWN;
-   }
+       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;
+       }
 
-   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"));
+       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 PJ_EUNKNOWN;
-   }
+       return status;
+}
 
-   return PJ_SUCCESS;
+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_ONHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
+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"));
 
@@ -409,7 +461,7 @@ static pj_status_t tapi_dev_event_ONHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
       return PJ_EUNKNOWN;
    }
 
-   /* enc/dec stop*/
+   /* enc/dec stop */
    if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
       TRACE_((THIS_FILE, "ERROR - codec start failed!"));
 
@@ -419,7 +471,7 @@ static pj_status_t tapi_dev_event_ONHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
    return PJ_SUCCESS;
 }
 
-static pj_status_t tapi_dev_event_OFFHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
+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"));
 
@@ -430,7 +482,7 @@ static pj_status_t tapi_dev_event_OFFHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx
       return PJ_EUNKNOWN;
    }
 
-   /* enc/dec stop*/
+   /* enc/dec stop */
    if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
       TRACE_((THIS_FILE, "ERROR - codec start failed!"));
 
@@ -440,70 +492,71 @@ static pj_status_t tapi_dev_event_OFFHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx
    return PJ_SUCCESS;
 }
 
-static pj_status_t tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
+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!"));
+       PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
 
-      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!"));
+       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;
+       }
 
-      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;
+       return PJ_SUCCESS;
 }
 
-static pj_status_t tapi_dev_event_handler(
-                     tapi_aud_stream_t *stream)
+static pj_status_t
+tapi_dev_event_handler(tapi_aud_stream_t *stream)
 {
-   tapi_ctx *dev_ctx = stream->dev_ctx;
-   pj_uint32_t dev_idx = stream->param.rec_id;
-   pj_status_t status = PJ_SUCCESS;
-   IFX_TAPI_EVENT_t tapiEvent;
-
-   memset (&tapiEvent, 0, sizeof(tapiEvent));
-
-   tapiEvent.ch = dev_ctx->data2phone_map[dev_idx];
-
-   /* Get event*/
-   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_ONHOOK(dev_ctx, dev_idx);
-           if(tapi_hook_callback)
-                  tapi_hook_callback(0);
-            break;
-         case IFX_TAPI_EVENT_FXS_OFFHOOK:
-            status = tapi_dev_event_OFFHOOK(dev_ctx, dev_idx);
-           if(tapi_hook_callback)
-                  tapi_hook_callback(1);
-            break;
-        case IFX_TAPI_EVENT_DTMF_DIGIT:
-           if(tapi_digit_callback)
-                  tapi_digit_callback(tapiEvent.data.dtmf.ascii);
-           break;
-        default:
-            printf("%s:%s[%d]%04X\n", __FILE__, __func__, __LINE__, tapiEvent.id);
-           break;
-      }
-   }
-
-   return status;
+       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)
-{
+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;
@@ -512,7 +565,7 @@ static pj_status_t tapi_dev_data_handler(
    pjmedia_frame frame_rec, frame_play;
    pj_int32_t ret;
 
-   /* Get data from driver*/
+   /* 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!"));
@@ -565,226 +618,195 @@ static pj_status_t tapi_dev_data_handler(
    return PJ_SUCCESS;
 }
 
-/* TAPI capture and playback thread. */
-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;
-   fd_set rfds, trfds;
-   pj_uint32_t width = 0;
-   struct timeval tv;
-   pj_uint32_t sretval;
-   pj_uint32_t dev_idx;
-
-   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;
-
-   FD_ZERO(&rfds);
-
-   FD_SET(dev_ctx->dev_fd, &rfds);
-   width = FD_WIDTH_SET(dev_ctx->dev_fd, width);
-
-   FD_SET(dev_ctx->ch_fd[dev_idx], &rfds);
-   width = FD_WIDTH_SET(dev_ctx->ch_fd[dev_idx], width);
-
-   tv.tv_sec = TAPI_LL_DEV_SELECT_TIMEOUT_MS / 1000;
-   tv.tv_usec = (TAPI_LL_DEV_SELECT_TIMEOUT_MS % 1000) * 1000; 
-
-   strm->run_flag = 1;
-
-   while(1)
-   {
-      /* Update the local file descriptor by the copy in the task parameter */
-      memcpy((void *) &trfds, (void*) &rfds, sizeof(fd_set));
-
-      sretval = select(width + 1, &trfds, NULL, NULL, &tv); 
-
-      if (!strm->run_flag) {
-         break;
-      }
-
-      /* error or timeout on select */
-      if (sretval <= 0) {
-         continue;
-      }
-
-      /* Check device control channel*/
-      if (FD_ISSET(dev_ctx->dev_fd, &trfds)) {
-        if (tapi_dev_event_handler(strm) != PJ_SUCCESS) {
-            PJ_LOG(1,(THIS_FILE, "TAPI: event hanldler failed!"));
-            break;
-         }
-      }
-
-      /* Check device data channel*/
-      if (FD_ISSET(dev_ctx->ch_fd[dev_idx], &trfds)) {
-        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;
+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
  ****************************************************************************/
 
-/*  Init tapi audio driver. */
-pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf)
-{
-    struct tapi_aud_factory *f;
-    pj_pool_t *pool;
+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()"));
+       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;
+       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;
+       return &f->base;
 }
 
-/* API: init factory */
-static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
+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()"));
-
-   /* Enumerate sound devices */
-   af->dev_count = TAPI_AUDIO_DEV_NUM;
-
-   af->dev_info = (pjmedia_aud_dev_info*)
-         pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
-
-   for (c = 0; c < af->dev_count; c++) {
-      pj_ansi_sprintf(af->dev_info[c].name,"%s_%02d", TAPI_BASE_NAME, c);
-
-      af->dev_info[c].input_count = af->dev_info[c].output_count = 1;
-      af->dev_info[c].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
-      pj_ansi_strcpy(af->dev_info[c].driver, "/dev/vmmc");
-
-      af->dev_info[c].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
-                             PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
-                             PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
-
-      af->dev_info[c].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
-   }
-
-   /* Initialize TAPI device(s)*/
-   if (tapi_dev_start(af) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
-      return PJ_EUNKNOWN;
-   }
-
-   return PJ_SUCCESS;
+       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;
 }
 
-/* API: destroy factory */
-static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
+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()"));
+       struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
+       pj_pool_t *pool;
+       pj_status_t status = PJ_SUCCESS;
 
-   /* Stop TAPI device*/
-   if (tapi_dev_stop(f) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
-      status = PJ_EUNKNOWN;
-   }
+       TRACE_((THIS_FILE, "factory_destroy()"));
 
-   pool = af->pool;
-   af->pool = NULL;
-   pj_pool_release(pool);
+       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;
+       return status;
 }
 
-/* API: get number of devices */
-static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
+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()"));
+       struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
+       TRACE_((THIS_FILE, "factory_get_dev_count()"));
 
-  return af->dev_count;
+       return af->dev_count;
 }
 
-/* API: get device info */
-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_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;
+       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);
+       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));
+       pj_memcpy(info, &af->dev_info[index], sizeof(*info));
 
-  return PJ_SUCCESS;
+       return PJ_SUCCESS;
 }
 
-/* API: create default device parameter */
-static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
-           unsigned index,
-           pjmedia_aud_param *param)
+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;
+       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;
 }
 
-/* API: create stream */
-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)
+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;
@@ -836,222 +858,160 @@ static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
    return PJ_SUCCESS;
 }
 
-/****************************************************************************
- * Stream operations
- */
-/* API: Get stream info. */
-static pj_status_t stream_get_param(pjmedia_aud_stream *s,
-                                    pjmedia_aud_param *pi)
+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));
-  /* Update the volume setting */
-  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;
+       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;
 }
 
-/* API: get capability */
-static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
-          pjmedia_aud_dev_cap cap,
-          void *pval)
+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;
-#ifdef OLD_IMPL
-  OSStatus status = 0;
-  PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL);
-
-  if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING && strm->play_strm->queue)
-  {
-    Float32 vol;
-    status = AudioQueueGetParameter(strm->play_strm->queue,
-                                    kAudioQueueParam_Volume, &vol);
-    if (!status)
-    {
-      *(unsigned*)pval = (vol * 100);
-      return PJ_SUCCESS;
-    }
-  }
-  else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY && strm->play_strm->queue)
-  {
-    Float32 lat;
-    UInt32 size = sizeof(lat);
-    status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency,
-                                     &size, &lat);
-    if (!status)
-    {
-      *(unsigned*)pval = lat * 1000;
-      return PJ_SUCCESS;
-    }
-  }
-  else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE && strm->play_strm->queue)
-  {
-    *(pjmedia_aud_dev_route*)pval = strm->param.output_route;
-    return PJ_SUCCESS;
-  }
-  else if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY && strm->rec_strm->queue)
-  {
-    Float32 lat;
-    UInt32 size = sizeof(lat);
-    status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency,
-                                     &size, &lat);
-    if (!status)
-    {
-      *(unsigned*)pval = lat * 1000;
-      return PJ_SUCCESS;
-    }
-  }
-
-  if (status)
-    PJ_LOG(1, (THIS_FILE, "AudioQueueGetParameter/AudioSessionGetProperty err %d", status));
-  return PJMEDIA_EAUD_INVCAP;
-#else
-  return PJ_SUCCESS;
-#endif
+       // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
+       return PJ_SUCCESS;
 }
 
-/* API: set capability */
-static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
-          pjmedia_aud_dev_cap cap,
-          const void *pval)
+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;
-#ifdef OLD_IMPL
-  OSStatus status = 0;
-  PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL);
-
-  if (strm->play_strm->queue)
-    switch (cap)
-    {
-      case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
-      {
-        /* Output volume setting */
-        unsigned vol = *(unsigned*)pval;
-        Float32 volume;
-
-        if (vol > 100)
-          vol = 100;
-        volume = vol / 100.;
-        status = AudioQueueSetParameter(strm->play_strm->queue, kAudioQueueParam_Volume,
-                                        volume);
-        if (!status)
-        {
-          PJ_LOG(1, (THIS_FILE, "AudioQueueSetParameter err %d", status));
-          return PJMEDIA_EAUD_SYSERR;
-        }
-        strm->param.output_vol = *(unsigned*)pval;
-        return PJ_SUCCESS;
-      }
-      case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
-      {
-        pjmedia_aud_dev_route r = *(const pjmedia_aud_dev_route*)pval;
-        UInt32 route = (r == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER ?
-            kAudioSessionOverrideAudioRoute_Speaker :
-            kAudioSessionOverrideAudioRoute_None);
-
-        status = AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
-                                          sizeof(route), &route);
-        if (status)
-        {
-          PJ_LOG(1, (THIS_FILE, "AudioSessionSetProperty err %d", status));
-          return PJMEDIA_EAUD_SYSERR;
-        }
-        strm->param.output_route = r;
-        return PJ_SUCCESS;
-      }
-      default:
-        return PJMEDIA_EAUD_INVCAP;
-    }
+       // 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;
 
-  return PJMEDIA_EAUD_INVCAP;
-#else
-  return PJ_SUCCESS;
-#endif
+       TRACE_((THIS_FILE, "stream_start()"));
+
+       dev_idx = strm->param.rec_id;
+
+       return PJ_SUCCESS;
 }
 
-/* API: Start stream. */
-static pj_status_t stream_start(pjmedia_aud_stream *s)
+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;
+       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()"));
+       TRACE_((THIS_FILE, "stream_stop()"));
+       dev_idx = strm->param.rec_id;
 
-   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;
+       return PJ_SUCCESS;
 }
 
-/* API: Stop stream. */
-static pj_status_t stream_stop(pjmedia_aud_stream *s)
+static pj_status_t
+stream_destroy(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;
+       pj_status_t state = PJ_SUCCESS;
+       struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
+       pj_pool_t *pool;
 
-   TRACE_((THIS_FILE, "stream_stop()"));
+       PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+       TRACE_((THIS_FILE, "stream_destroy()"));
 
-   dev_idx = strm->param.rec_id;
+       stream_stop(stream);
+       stream->run_flag = 0;
 
-   /* enc/dec stop*/
-   if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
-      TRACE_((THIS_FILE, "ERROR - codec start failed!"));
+       if (stream->thread)
+       {
+               pj_thread_join(stream->thread);
+               pj_thread_destroy(stream->thread);
+               stream->thread = NULL;
+       }
 
-      return PJ_EUNKNOWN;
-   }
+       pool = stream->pool;
+       pj_bzero(stream, sizeof(stream));
+       pj_pool_release(pool);
 
-   return PJ_SUCCESS;
+       return state;
 }
 
-/* API: Destroy stream. */
-static pj_status_t stream_destroy(pjmedia_aud_stream *s)
+pj_status_t
+tapi_hook_status(pj_uint32_t port, pj_uint32_t *status)
 {
-   pj_status_t state = PJ_SUCCESS;
-   struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
-   pj_pool_t *pool;
+       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_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+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;
+}
 
-   TRACE_((THIS_FILE, "stream_destroy()"));
+pj_status_t
+tapi_dial_tone(pj_uint32_t port) {
+       PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
 
-   stream_stop(stream);
+       ioctl(ch_fd[port], IFX_TAPI_TONE_DIALTONE_PLAY, 0);
 
-   stream->run_flag = 0;
+       return PJ_SUCCESS;
+}
 
-   /* Stop the stream thread */
-   if (stream->thread)
-   {
-      pj_thread_join(stream->thread);
-      pj_thread_destroy(stream->thread);
-      stream->thread = NULL;
-   }
+pj_status_t
+tapi_no_tone(pj_uint32_t port) {
+       PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
 
-   pool = stream->pool;
-   pj_bzero(stream, sizeof(stream));
-   pj_pool_release(pool);
+       ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
 
-   return state;
+       return PJ_SUCCESS;
 }
 
-#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */
+#endif