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