Root/package/pjsip/patches/0002-register-tapi.patch

1From 455f6f2234a36aeeb97d3e05e9cbe3afad147341 Mon Sep 17 00:00:00 2001
2From: John Crispin <blogic@openwrt.org>
3Date: Sat, 28 Jan 2012 21:43:49 +0100
4Subject: [PATCH 2/3] register tapi
5
6---
7 .../pjmedia/src/pjmedia-audiodev/audiodev.c | 7 +
8 .../pjmedia/src/pjmedia-audiodev/tapi_dev.c | 1300 ++++++++++++++++++++
9 2 files changed, 1307 insertions(+), 0 deletions(-)
10 create mode 100644 pjproject-1.12/pjmedia/src/pjmedia-audiodev/tapi_dev.c
11
12diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
13index 3b7e121..82b364c 100644
14--- a/pjmedia/src/pjmedia-audiodev/audiodev.c
15+++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
16@@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf);
17 pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
18 #endif
19 
20+#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
21+pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf);
22+#endif
23+
24 #define MAX_DRIVERS 16
25 #define MAX_DEVS 64
26 
27@@ -409,6 +413,9 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
28 #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
29     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
30 #endif
31+#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
32+ aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_tapi_factory;
33+#endif
34 
35     /* Initialize each factory and build the device ID list */
36     for (i=0; i<aud_subsys.drv_cnt; ++i) {
37diff --git a/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
38new file mode 100644
39index 0000000..2c65a0d
40--- /dev/null
41+++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
42@@ -0,0 +1,1300 @@
43+/******************************************************************************
44+
45+ Copyright (c) 2010
46+ Lantiq Deutschland GmbH
47+ Am Campeon 3; 85579 Neubiberg, Germany
48+
49+ For licensing information, see the file 'LICENSE' in the root folder of
50+ this software module.
51+
52+******************************************************************************/
53+#include <pjmedia-audiodev/audiodev_imp.h>
54+#include <pjmedia/errno.h>
55+#include <pj/assert.h>
56+#include <pj/pool.h>
57+#include <pj/log.h>
58+#include <pj/os.h>
59+
60+#if defined(PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE) && PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
61+
62+/* Linux includes */
63+#include <stdio.h>
64+#include <string.h>
65+#include <stdlib.h>
66+#include <ctype.h>
67+#include <sys/stat.h>
68+#include <fcntl.h>
69+#include <sys/types.h>
70+#include <sys/ioctl.h>
71+#include <sys/select.h>
72+#include <sys/time.h>
73+#include <unistd.h>
74+#include <poll.h>
75+
76+/* TAPI includes */
77+#include "drv_tapi_io.h"
78+#include "vmmc_io.h"
79+
80+/* Maximum 2 devices */
81+#define TAPI_AUDIO_PORT_NUM 2
82+#define TAPI_BASE_NAME "TAPI"
83+#define TAPI_LL_DEV_BASE_PATH "/dev/vmmc"
84+#define TAPI_LL_DEV_FIRMWARE_NAME "/lib/firmware/danube_firmware.bin"
85+#define TAPI_LL_BBD_NAME "/lib/firmware/danube_bbd_fxs.bin"
86+
87+#define TAPI_LL_DEV_SELECT_TIMEOUT_MS 2000
88+#define TAPI_LL_DEV_MAX_PACKET_SIZE 800
89+#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE 12
90+#define TAPI_LL_DEV_ENC_FRAME_LEN_MS 20
91+#define TAPI_LL_DEV_ENC_SMPL_PER_SEC 8000
92+#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS 16
93+#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME 160
94+#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
95+
96+#define THIS_FILE "tapi_dev.c"
97+
98+/* Set to 1 to enable tracing */
99+#if 1
100+# define TRACE_(expr) PJ_LOG(1,expr)
101+#else
102+# define TRACE_(expr)
103+#endif
104+
105+pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
106+
107+typedef struct
108+{
109+ pj_int32_t dev_fd;
110+ pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
111+ pj_int8_t data2phone_map[TAPI_AUDIO_PORT_NUM];
112+} tapi_ctx;
113+
114+struct tapi_aud_factory
115+{
116+ pjmedia_aud_dev_factory base;
117+ pj_pool_t *pool;
118+ pj_pool_factory *pf;
119+ pj_uint32_t dev_count;
120+ pjmedia_aud_dev_info *dev_info;
121+ tapi_ctx dev_ctx;
122+};
123+
124+typedef struct tapi_aud_factory tapi_aud_factory_t;
125+
126+struct tapi_aud_stream
127+{
128+ pjmedia_aud_stream base;
129+ pj_pool_t *pool;
130+ pjmedia_aud_param param;
131+ pjmedia_aud_rec_cb rec_cb;
132+ pjmedia_aud_play_cb play_cb;
133+ void *user_data;
134+
135+ pj_thread_desc thread_desc;
136+ pj_thread_t *thread;
137+ tapi_ctx *dev_ctx;
138+ pj_uint8_t run_flag;
139+ pj_timestamp timestamp;
140+};
141+
142+typedef struct tapi_aud_stream tapi_aud_stream_t;
143+
144+/* Factory prototypes */
145+static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
146+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
147+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
148+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
149+ unsigned index,
150+ pjmedia_aud_dev_info *info);
151+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
152+ unsigned index,
153+ pjmedia_aud_param *param);
154+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
155+ const pjmedia_aud_param *param,
156+ pjmedia_aud_rec_cb rec_cb,
157+ pjmedia_aud_play_cb play_cb,
158+ void *user_data,
159+ pjmedia_aud_stream **p_aud_strm);
160+
161+/* Stream prototypes */
162+static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
163+ pjmedia_aud_param *param);
164+static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
165+ pjmedia_aud_dev_cap cap,
166+ void *value);
167+static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
168+ pjmedia_aud_dev_cap cap,
169+ const void *value);
170+static pj_status_t stream_start(pjmedia_aud_stream *strm);
171+static pj_status_t stream_stop(pjmedia_aud_stream *strm);
172+static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
173+
174+static pjmedia_aud_dev_factory_op tapi_fact_op =
175+{
176+ &factory_init,
177+ &factory_destroy,
178+ &factory_get_dev_count,
179+ &factory_get_dev_info,
180+ &factory_default_param,
181+ &factory_create_stream
182+};
183+
184+static pjmedia_aud_stream_op tapi_strm_op =
185+{
186+ &stream_get_param,
187+ &stream_get_cap,
188+ &stream_set_cap,
189+ &stream_start,
190+ &stream_stop,
191+ &stream_destroy
192+};
193+
194+/* TAPI configuration */
195+static struct tapi_aud_stream streams[TAPI_AUDIO_PORT_NUM];
196+
197+void (*tapi_digit_callback)(pj_uint8_t port, pj_uint8_t digit) = NULL;
198+void (*tapi_hook_callback)(pj_uint8_t port, pj_uint8_t event) = NULL;
199+
200+#define TAPI_TONE_LOCALE_NONE 32
201+#define TAPI_TONE_LOCALE_BUSY_CODE 33
202+#define TAPI_TONE_LOCALE_CONGESTION_CODE 34
203+#define TAPI_TONE_LOCALE_DIAL_CODE 35
204+#define TAPI_TONE_LOCALE_RING_CODE 36
205+#define TAPI_TONE_LOCALE_WAITING_CODE 37
206+
207+static pj_uint8_t tapi_channel_revert = 0;
208+static pj_uint8_t tapi_cid_type = 0;
209+static pj_uint8_t tapi_locale = 0;
210+
211+void tapi_revert_channels(void)
212+{
213+ tapi_channel_revert = 1;
214+ PJ_LOG(3, (THIS_FILE, "using reverted configuration for TAPI channels"));
215+}
216+
217+void tapi_cid_select(char *cid)
218+{
219+ if (!stricmp(cid, "telecordia")) {
220+ tapi_cid_type = IFX_TAPI_CID_STD_TELCORDIA;
221+ PJ_LOG(3, (THIS_FILE, "using TELECORDIA configuration for TAPI CID"));
222+ } else if (!stricmp(cid, "etsi_fsk")) {
223+ tapi_cid_type = IFX_TAPI_CID_STD_ETSI_FSK;
224+ PJ_LOG(3, (THIS_FILE, "using ETSI FSK configuration for TAPI CID"));
225+ } else if (!stricmp(cid, "etsi_dtmf")) {
226+ tapi_cid_type = IFX_TAPI_CID_STD_ETSI_DTMF;
227+ PJ_LOG(3, (THIS_FILE, "using ETSI DTMF configuration for TAPI CID"));
228+ } else if (!stricmp(cid, "sin")) {
229+ tapi_cid_type = IFX_TAPI_CID_STD_SIN;
230+ PJ_LOG(3, (THIS_FILE, "using SIN CID configuration for TAPI CID"));
231+ } else if (!stricmp(cid, "ntt")) {
232+ tapi_cid_type = IFX_TAPI_CID_STD_NTT;
233+ PJ_LOG(3, (THIS_FILE, "using NTT configuration for TAPI CID"));
234+ } else if (!stricmp(cid, "kpn_dtmf")) {
235+ tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF;
236+ PJ_LOG(3, (THIS_FILE, "using KPN DTMF configuration for TAPI CID"));
237+ } else if (!stricmp(cid, "kpn_dtmf_fsk")) {
238+ tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF_FSK;
239+ PJ_LOG(3, (THIS_FILE, "using KPN DTMF FSK configuration for TAPI CID"));
240+ }
241+}
242+
243+void tapi_locale_select(char *country)
244+{
245+ IFX_TAPI_TONE_t tone;
246+ pj_status_t status;
247+ pj_uint8_t c;
248+
249+ tapi_locale = 1;
250+
251+ if (!stricmp(country, "croatia")) {
252+ PJ_LOG(3, (THIS_FILE, "using localized tones for Croatia"));
253+
254+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
255+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
256+ tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
257+ tone.simple.freqA = 425;
258+ tone.simple.levelA = 0;
259+ tone.simple.cadence[0] = 500;
260+ tone.simple.cadence[1] = 500;
261+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
262+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
263+ tone.simple.loop = 0;
264+ tone.simple.pause = 0;
265+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
266+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
267+ if (status != PJ_SUCCESS)
268+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
269+ }
270+
271+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
272+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
273+ tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
274+ tone.simple.freqA = 425;
275+ tone.simple.levelA = 0;
276+ tone.simple.cadence[0] = 250;
277+ tone.simple.cadence[1] = 250;
278+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
279+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
280+ tone.simple.loop = 0;
281+ tone.simple.pause = 0;
282+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
283+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
284+ if (status != PJ_SUCCESS)
285+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
286+ }
287+
288+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
289+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
290+ tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
291+ tone.simple.freqA = 425;
292+ tone.simple.levelA = 0;
293+ tone.simple.cadence[0] = 200;
294+ tone.simple.cadence[1] = 300;
295+ tone.simple.cadence[2] = 700;
296+ tone.simple.cadence[3] = 800;
297+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
298+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
299+ tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
300+ tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
301+ tone.simple.loop = 0;
302+ tone.simple.pause = 0;
303+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
304+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
305+ if (status != PJ_SUCCESS)
306+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
307+ }
308+
309+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
310+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
311+ tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
312+ tone.simple.freqA = 425;
313+ tone.simple.levelA = 0;
314+ tone.simple.cadence[0] = 1000;
315+ tone.simple.cadence[1] = 4000;
316+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
317+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
318+ tone.simple.loop = 0;
319+ tone.simple.pause = 0;
320+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
321+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
322+ if (status != PJ_SUCCESS)
323+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
324+ }
325+
326+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
327+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
328+ tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
329+ tone.simple.freqA = 425;
330+ tone.simple.levelA = 0;
331+ tone.simple.cadence[0] = 300;
332+ tone.simple.cadence[1] = 8000;
333+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
334+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
335+ tone.simple.loop = 0;
336+ tone.simple.pause = 0;
337+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
338+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
339+ if (status != PJ_SUCCESS)
340+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
341+ }
342+ } else if (!stricmp(country, "germany")) {
343+ PJ_LOG(3, (THIS_FILE, "using localized tones for Germany"));
344+
345+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
346+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
347+ tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
348+ tone.simple.freqA = 425;
349+ tone.simple.levelA = 0;
350+ tone.simple.cadence[0] = 480;
351+ tone.simple.cadence[1] = 480;
352+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
353+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
354+ tone.simple.loop = 0;
355+ tone.simple.pause = 0;
356+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
357+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
358+ if (status != PJ_SUCCESS)
359+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
360+ }
361+
362+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
363+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
364+ tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
365+ tone.simple.freqA = 425;
366+ tone.simple.levelA = 0;
367+ tone.simple.cadence[0] = 240;
368+ tone.simple.cadence[1] = 240;
369+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
370+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
371+ tone.simple.loop = 0;
372+ tone.simple.pause = 0;
373+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
374+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
375+ if (status != PJ_SUCCESS)
376+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
377+ }
378+
379+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
380+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
381+ tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
382+ tone.simple.freqA = 425;
383+ tone.simple.levelA = 0;
384+ tone.simple.cadence[0] = 1000;
385+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
386+ tone.simple.loop = 0;
387+ tone.simple.pause = 0;
388+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
389+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
390+ if (status != PJ_SUCCESS)
391+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
392+ }
393+
394+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
395+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
396+ tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
397+ tone.simple.freqA = 425;
398+ tone.simple.levelA = 0;
399+ tone.simple.cadence[0] = 1000;
400+ tone.simple.cadence[1] = 4000;
401+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
402+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
403+ tone.simple.loop = 0;
404+ tone.simple.pause = 0;
405+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
406+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
407+ if (status != PJ_SUCCESS)
408+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
409+ }
410+
411+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
412+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
413+ tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
414+ tone.simple.freqA = 425;
415+ tone.simple.levelA = 0;
416+ tone.simple.cadence[0] = 200;
417+ tone.simple.cadence[1] = 200;
418+ tone.simple.cadence[2] = 200;
419+ tone.simple.cadence[3] = 5000;
420+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
421+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
422+ tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
423+ tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
424+ tone.simple.loop = 0;
425+ tone.simple.pause = 0;
426+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
427+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
428+ if (status != PJ_SUCCESS)
429+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
430+ }
431+ }
432+}
433+
434+static pj_int32_t
435+tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
436+{
437+ char devname[128] = { 0 };
438+ pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
439+ return open((const char*)devname, O_RDWR, 0644);
440+}
441+
442+static pj_status_t
443+tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
444+{
445+ pj_status_t status = PJ_SUCCESS;
446+ FILE *fd;
447+ struct stat file_stat;
448+
449+ fd = fopen(pPath, "rb");
450+ if (fd == NULL) {
451+ TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath));
452+ return PJ_EUNKNOWN;
453+ }
454+
455+ if (stat(pPath, &file_stat) != 0) {
456+ TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath));
457+ return PJ_EUNKNOWN;
458+ }
459+
460+ *ppBuf = malloc(file_stat.st_size);
461+ if (*ppBuf == NULL) {
462+ TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath));
463+ status = PJ_EUNKNOWN;
464+ goto on_exit;
465+ }
466+
467+ if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
468+ TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
469+ status = PJ_EUNKNOWN;
470+ goto on_exit;
471+ }
472+
473+ *pBufSz = file_stat.st_size;
474+
475+on_exit:
476+ if (fd != NULL)
477+ fclose(fd);
478+
479+ if (*ppBuf != NULL && status != PJ_SUCCESS)
480+ free(*ppBuf);
481+
482+ return status;
483+}
484+
485+static void
486+tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
487+{
488+ if (pBuf != NULL)
489+ free(pBuf);
490+}
491+
492+static pj_status_t
493+tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
494+{
495+ pj_status_t status = PJ_SUCCESS;
496+ pj_uint8_t *pFirmware = NULL;
497+ pj_uint32_t binSz = 0;
498+ VMMC_IO_INIT vmmc_io_init;
499+
500+ status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
501+ if (status != PJ_SUCCESS) {
502+ TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
503+ return PJ_EUNKNOWN;
504+ }
505+
506+ memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
507+ vmmc_io_init.pPRAMfw = pFirmware;
508+ vmmc_io_init.pram_size = binSz;
509+
510+ status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
511+ if (status != PJ_SUCCESS)
512+ TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!"));
513+
514+ tapi_dev_binary_buffer_delete(pFirmware);
515+
516+ return status;
517+}
518+
519+/* NOT USED */
520+#if 0
521+static int
522+tapi_dev_bbd_download(int fd, const char *pPath)
523+{
524+ int status = PJ_SUCCESS;
525+ unsigned char *pFirmware = NULL;
526+ unsigned int binSz = 0;
527+ VMMC_DWLD_t bbd_data;
528+
529+
530+ /* Create binary buffer */
531+ status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
532+ if (status != PJ_SUCCESS) {
533+ TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
534+ return status;
535+ }
536+
537+ /* Download Voice Firmware */
538+ memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
539+ bbd_data.buf = pFirmware;
540+ bbd_data.size = binSz;
541+
542+ status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
543+ if (status != PJ_SUCCESS) {
544+ TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
545+ }
546+
547+ /* Delete binary buffer */
548+ tapi_dev_binary_buffer_delete(pFirmware);
549+
550+ return status;
551+}
552+#endif
553+
554+static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
555+{
556+ pj_uint8_t c, hook_status;
557+ IFX_TAPI_TONE_t tone;
558+ IFX_TAPI_DEV_START_CFG_t tapistart;
559+ IFX_TAPI_MAP_DATA_t datamap;
560+ IFX_TAPI_ENC_CFG_t enc_cfg;
561+ IFX_TAPI_LINE_VOLUME_t line_vol;
562+ IFX_TAPI_WLEC_CFG_t lec_cfg;
563+ IFX_TAPI_JB_CFG_t jb_cfg;
564+ IFX_TAPI_CID_CFG_t cid_cfg;
565+ pj_status_t status;
566+
567+ /* Open device */
568+ f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
569+
570+ if (f->dev_ctx.dev_fd < 0) {
571+ TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
572+ return PJ_EUNKNOWN;
573+ }
574+
575+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
576+ if (tapi_channel_revert)
577+ ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, c + 1);
578+ else
579+ ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
580+
581+ if (f->dev_ctx.dev_fd < 0) {
582+ TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
583+ return PJ_EUNKNOWN;
584+ }
585+ if (tapi_channel_revert)
586+ f->dev_ctx.data2phone_map[c] = c & 0x1 ? 1 : 0;
587+ else
588+ f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
589+ }
590+
591+ status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
592+ if (status != PJ_SUCCESS) {
593+ TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
594+ return PJ_EUNKNOWN;
595+ }
596+
597+ /* Download coefficients */
598+ /*
599+ status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
600+ if (status != PJ_SUCCESS) {
601+ TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
602+ return PJ_EUNKNOWN;
603+ }
604+ */
605+
606+ memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
607+ tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
608+
609+ /* Start TAPI */
610+ status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
611+ if (status != PJ_SUCCESS) {
612+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
613+ return PJ_EUNKNOWN;
614+ }
615+
616+
617+ /* OpenWrt default tone */
618+ memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
619+ tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
620+ tone.simple.index = TAPI_TONE_LOCALE_NONE;
621+ tone.simple.freqA = 400;
622+ tone.simple.levelA = 0;
623+ tone.simple.freqB = 450;
624+ tone.simple.levelB = 0;
625+ tone.simple.freqC = 550;
626+ tone.simple.levelC = 0;
627+ tone.simple.freqD = 600;
628+ tone.simple.levelD = 0;
629+ tone.simple.cadence[0] = 100;
630+ tone.simple.cadence[1] = 150;
631+ tone.simple.cadence[2] = 100;
632+ tone.simple.cadence[3] = 150;
633+ tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA | IFX_TAPI_TONE_FREQB;
634+ tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
635+ tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQC | IFX_TAPI_TONE_FREQD;
636+ tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
637+ tone.simple.loop = 0;
638+ tone.simple.pause = 0;
639+ for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
640+ /* OpenWrt default tone */
641+ status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
642+ if (status != PJ_SUCCESS)
643+ TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
644+
645+ /* Perform mapping */
646+ memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
647+ datamap.nDstCh = f->dev_ctx.data2phone_map[c];
648+ datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
649+
650+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
651+ if (status != PJ_SUCCESS) {
652+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
653+ return PJ_EUNKNOWN;
654+ }
655+
656+ /* Set Line feed */
657+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
658+ if (status != PJ_SUCCESS) {
659+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
660+ return PJ_EUNKNOWN;
661+ }
662+
663+ /* Configure encoder for linear stream */
664+ memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
665+ enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
666+ enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8;
667+
668+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
669+ if (status != PJ_SUCCESS) {
670+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
671+ return PJ_EUNKNOWN;
672+ }
673+
674+ /* Suppress TAPI volume, otherwise PJSIP starts autogeneration */
675+ memset(&line_vol, 0, sizeof(line_vol));
676+ line_vol.nGainRx = -8;
677+ line_vol.nGainTx = -8;
678+
679+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
680+ if (status != PJ_SUCCESS) {
681+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
682+ return PJ_EUNKNOWN;
683+ }
684+
685+ /* Configure line echo canceller */
686+ memset(&lec_cfg, 0, sizeof(lec_cfg));
687+ lec_cfg.nType = IFX_TAPI_WLEC_TYPE_NFE;
688+ lec_cfg.bNlp = IFX_TAPI_LEC_NLP_OFF;
689+
690+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_WLEC_PHONE_CFG_SET, &lec_cfg);
691+ if (status != PJ_SUCCESS) {
692+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_WLEC_PHONE_CFG_SET ioctl failed"));
693+ return PJ_EUNKNOWN;
694+ }
695+
696+ /* Configure jitter buffer */
697+ memset(&jb_cfg, 0, sizeof(jb_cfg));
698+ jb_cfg.nJbType = IFX_TAPI_JB_TYPE_ADAPTIVE;
699+ jb_cfg.nPckAdpt = IFX_TAPI_JB_PKT_ADAPT_VOICE;
700+ jb_cfg.nLocalAdpt = IFX_TAPI_JB_LOCAL_ADAPT_ON;
701+ jb_cfg.nScaling = 0x10;
702+ jb_cfg.nInitialSize = 0x2d0;
703+ jb_cfg.nMinSize = 0x50;
704+ jb_cfg.nMaxSize = 0x5a0;
705+
706+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_JB_CFG_SET, &jb_cfg);
707+ if (status != PJ_SUCCESS) {
708+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_JB_CFG_SET ioctl failed"));
709+ return PJ_EUNKNOWN;
710+ }
711+
712+ /* Configure Caller ID type */
713+ if (tapi_cid_type) {
714+ memset(&cid_cfg, 0, sizeof(cid_cfg));
715+ cid_cfg.nStandard = tapi_cid_type;
716+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cfg);
717+ if (status != PJ_SUCCESS) {
718+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
719+ return PJ_EUNKNOWN;
720+ }
721+ }
722+
723+ /* check hook status */
724+ hook_status = 0;
725+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
726+ if (status != PJ_SUCCESS) {
727+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
728+ return PJ_EUNKNOWN;
729+ }
730+
731+ /* if off hook do initialization */
732+ if (hook_status) {
733+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
734+ if (status != PJ_SUCCESS) {
735+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
736+ return PJ_EUNKNOWN;
737+ }
738+ status = ioctl(c, IFX_TAPI_ENC_START, 0);
739+ if (status != PJ_SUCCESS) {
740+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
741+ return PJ_EUNKNOWN;
742+ }
743+
744+ status = ioctl(c, IFX_TAPI_DEC_START, 0);
745+ if (status != PJ_SUCCESS) {
746+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
747+ return PJ_EUNKNOWN;
748+ }
749+ }
750+ }
751+
752+ return status;
753+}
754+
755+static pj_status_t
756+tapi_dev_stop(tapi_aud_factory_t *f)
757+{
758+ pj_status_t status = PJ_SUCCESS;
759+ pj_uint8_t c;
760+
761+ if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
762+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
763+ status = PJ_EUNKNOWN;
764+ }
765+
766+ close(f->dev_ctx.dev_fd);
767+ for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
768+ close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
769+
770+ return status;
771+}
772+
773+static pj_status_t
774+tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
775+{
776+ if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
777+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
778+ start ? "START" : "STOP"));
779+ return PJ_EUNKNOWN;
780+ }
781+
782+ if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
783+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
784+ start ? "START" : "STOP"));
785+ return PJ_EUNKNOWN;
786+ }
787+
788+ return PJ_SUCCESS;
789+}
790+
791+static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
792+{
793+ PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
794+
795+ if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
796+ IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
797+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
798+ return PJ_EUNKNOWN;
799+ }
800+
801+ /* enc/dec stop */
802+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
803+ TRACE_((THIS_FILE, "ERROR - codec start failed!"));
804+ return PJ_EUNKNOWN;
805+ }
806+
807+ return PJ_SUCCESS;
808+}
809+
810+static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
811+{
812+ PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
813+
814+ if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
815+ IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
816+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
817+ return PJ_EUNKNOWN;
818+ }
819+
820+ /* enc/dec stop */
821+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
822+ TRACE_((THIS_FILE, "ERROR - codec start failed!"));
823+ return PJ_EUNKNOWN;
824+ }
825+
826+ return PJ_SUCCESS;
827+}
828+
829+static pj_status_t
830+tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
831+{
832+ PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
833+
834+ if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
835+ IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
836+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
837+ return PJ_EUNKNOWN;
838+ }
839+
840+ /* enc/dec stop */
841+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
842+ TRACE_((THIS_FILE, "ERROR - codec start failed!"));
843+ return PJ_EUNKNOWN;
844+ }
845+
846+ return PJ_SUCCESS;
847+}
848+
849+static pj_status_t
850+tapi_dev_event_handler(tapi_aud_stream_t *stream)
851+{
852+ IFX_TAPI_EVENT_t tapiEvent;
853+ tapi_ctx *dev_ctx = stream->dev_ctx;
854+ pj_status_t status = PJ_SUCCESS;
855+ unsigned int i;
856+
857+ for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
858+ memset (&tapiEvent, 0, sizeof(tapiEvent));
859+ tapiEvent.ch = dev_ctx->data2phone_map[i];
860+ status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
861+
862+ if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
863+ switch(tapiEvent.id) {
864+ case IFX_TAPI_EVENT_FXS_ONHOOK:
865+ status = tapi_dev_event_on_hook(dev_ctx, i);
866+ if(tapi_hook_callback)
867+ tapi_hook_callback(i, 0);
868+ break;
869+ case IFX_TAPI_EVENT_FXS_OFFHOOK:
870+ status = tapi_dev_event_off_hook(dev_ctx, i);
871+ if(tapi_hook_callback)
872+ tapi_hook_callback(i, 1);
873+ break;
874+ case IFX_TAPI_EVENT_DTMF_DIGIT:
875+ if(tapi_digit_callback)
876+ tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
877+ break;
878+ case IFX_TAPI_EVENT_COD_DEC_CHG:
879+ case IFX_TAPI_EVENT_TONE_GEN_END:
880+ case IFX_TAPI_EVENT_CID_TX_SEQ_END:
881+ break;
882+ default:
883+ PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
884+ break;
885+ }
886+ }
887+ }
888+
889+ return status;
890+}
891+
892+static pj_status_t
893+tapi_dev_data_handler(tapi_aud_stream_t *stream) {
894+ pj_status_t status = PJ_SUCCESS;
895+ tapi_ctx *dev_ctx = stream->dev_ctx;
896+ pj_uint32_t dev_idx = stream->param.rec_id;
897+ pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
898+ pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
899+ pjmedia_frame frame_rec, frame_play;
900+ pj_int32_t ret;
901+
902+ /* Get data from driver */
903+ ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
904+ if (ret < 0) {
905+ TRACE_((THIS_FILE, "ERROR - no data available from device!"));
906+ return PJ_EUNKNOWN;
907+ }
908+
909+ if (ret > 0) {
910+ frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
911+ frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
912+ frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
913+ frame_rec.timestamp.u64 = stream->timestamp.u64;
914+
915+ status = stream->rec_cb(stream->user_data, &frame_rec);
916+ if (status != PJ_SUCCESS)
917+ PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
918+
919+ frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
920+ frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
921+ frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
922+ frame_play.timestamp.u64 = stream->timestamp.u64;
923+
924+ status = (*stream->play_cb)(stream->user_data, &frame_play);
925+ if (status != PJ_SUCCESS) {
926+ PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
927+ } else {
928+ memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
929+
930+ ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
931+
932+ if (ret < 0) {
933+ PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
934+ return PJ_EUNKNOWN;
935+ }
936+
937+ if (ret == 0) {
938+ PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
939+ return PJ_EUNKNOWN;
940+ }
941+ }
942+
943+ stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
944+ }
945+
946+ return PJ_SUCCESS;
947+}
948+
949+static int
950+PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
951+ tapi_ctx *dev_ctx = streams[0].dev_ctx;
952+ pj_uint32_t sretval;
953+ struct pollfd fds[3];
954+
955+ PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
956+
957+ streams[0].run_flag = 1;
958+ streams[1].run_flag = 1;
959+
960+ fds[0].fd = dev_ctx->dev_fd;
961+ fds[0].events = POLLIN;
962+ fds[1].fd = dev_ctx->ch_fd[0];
963+ fds[1].events = POLLIN;
964+ fds[2].fd = dev_ctx->ch_fd[1];
965+ fds[2].events = POLLIN;
966+
967+ while(1)
968+ {
969+ sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
970+
971+ if (!streams[0].run_flag && !streams[0].run_flag)
972+ break;
973+ if (sretval <= 0)
974+ continue;
975+
976+ if (fds[0].revents == POLLIN) {
977+ if (tapi_dev_event_handler(&streams[0]) != PJ_SUCCESS) {
978+ PJ_LOG(1, (THIS_FILE, "TAPI: event hanldler failed"));
979+ break;
980+ }
981+ }
982+
983+ if (fds[1].revents == POLLIN) {
984+ if (tapi_dev_data_handler(&streams[0]) != PJ_SUCCESS) {
985+ PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
986+ break;
987+ }
988+ }
989+
990+ if (fds[2].revents == POLLIN) {
991+ if (tapi_dev_data_handler(&streams[1]) != PJ_SUCCESS) {
992+ PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
993+ break;
994+ }
995+ }
996+ }
997+ PJ_LOG(1, (THIS_FILE, "TAPI: thread stopping..."));
998+
999+ return 0;
1000+}
1001+
1002+/* Factory operations */
1003+
1004+pjmedia_aud_dev_factory*
1005+pjmedia_tapi_factory(pj_pool_factory *pf) {
1006+ struct tapi_aud_factory *f;
1007+ pj_pool_t *pool;
1008+
1009+ TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
1010+
1011+ pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
1012+ f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
1013+ f->pf = pf;
1014+ f->pool = pool;
1015+ f->base.op = &tapi_fact_op;
1016+
1017+ return &f->base;
1018+}
1019+
1020+static pj_status_t
1021+factory_init(pjmedia_aud_dev_factory *f)
1022+{
1023+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1024+ pj_uint8_t i;
1025+
1026+ TRACE_((THIS_FILE, "factory_init()"));
1027+
1028+ af->dev_count = TAPI_AUDIO_PORT_NUM;
1029+ af->dev_info = (pjmedia_aud_dev_info*)
1030+ pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
1031+ for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
1032+ pj_ansi_sprintf(af->dev_info[i].name,"%s_%02d", TAPI_BASE_NAME, i);
1033+ af->dev_info[i].input_count = af->dev_info[i].output_count = 1;
1034+ af->dev_info[i].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
1035+ pj_ansi_strcpy(af->dev_info[i].driver, "/dev/vmmc");
1036+ af->dev_info[i].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
1037+ PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
1038+ PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1039+ af->dev_info[i].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
1040+ }
1041+ if (tapi_dev_start(af) != PJ_SUCCESS) {
1042+ TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
1043+ return PJ_EUNKNOWN;
1044+ }
1045+
1046+ return PJ_SUCCESS;
1047+}
1048+
1049+static pj_status_t
1050+factory_destroy(pjmedia_aud_dev_factory *f)
1051+{
1052+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1053+ pj_pool_t *pool;
1054+ pj_status_t status = PJ_SUCCESS;
1055+
1056+ TRACE_((THIS_FILE, "factory_destroy()"));
1057+
1058+ if (tapi_dev_stop(af) != PJ_SUCCESS) {
1059+ TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
1060+ status = PJ_EUNKNOWN;
1061+ }
1062+ pool = af->pool;
1063+ af->pool = NULL;
1064+ pj_pool_release(pool);
1065+
1066+ return status;
1067+}
1068+
1069+static unsigned
1070+factory_get_dev_count(pjmedia_aud_dev_factory *f)
1071+{
1072+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1073+ TRACE_((THIS_FILE, "factory_get_dev_count()"));
1074+
1075+ return af->dev_count;
1076+}
1077+
1078+static pj_status_t
1079+factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
1080+{
1081+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1082+
1083+ TRACE_((THIS_FILE, "factory_get_dev_info()"));
1084+ PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1085+
1086+ pj_memcpy(info, &af->dev_info[index], sizeof(*info));
1087+
1088+ return PJ_SUCCESS;
1089+}
1090+
1091+static pj_status_t
1092+factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
1093+{
1094+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1095+ struct pjmedia_aud_dev_info *di = &af->dev_info[index];
1096+
1097+ TRACE_((THIS_FILE, "factory_default_param."));
1098+ PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1099+
1100+ pj_bzero(param, sizeof(*param));
1101+ if (di->input_count && di->output_count) {
1102+ param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
1103+ param->rec_id = index;
1104+ param->play_id = index;
1105+ } else if (di->input_count) {
1106+ param->dir = PJMEDIA_DIR_CAPTURE;
1107+ param->rec_id = index;
1108+ param->play_id = PJMEDIA_AUD_INVALID_DEV;
1109+ } else if (di->output_count) {
1110+ param->dir = PJMEDIA_DIR_PLAYBACK;
1111+ param->play_id = index;
1112+ param->rec_id = PJMEDIA_AUD_INVALID_DEV;
1113+ } else {
1114+ return PJMEDIA_EAUD_INVDEV;
1115+ }
1116+
1117+ param->clock_rate = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
1118+ param->channel_count = 1;
1119+ param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
1120+ param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
1121+ param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
1122+ param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
1123+
1124+ return PJ_SUCCESS;
1125+}
1126+
1127+
1128+static pj_status_t
1129+factory_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param,
1130+ pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb,
1131+ void *user_data, pjmedia_aud_stream **p_aud_strm)
1132+{
1133+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1134+ pj_pool_t *pool;
1135+ pj_status_t status;
1136+ int id = param->rec_id;
1137+ struct tapi_aud_stream *strm = &streams[param->rec_id];
1138+ TRACE_((THIS_FILE, "factory_create_stream() rec_id:%d play_id:%d", param->rec_id, param->play_id));
1139+
1140+ /* Can only support 16bits per sample */
1141+ PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
1142+ PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
1143+ PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
1144+
1145+ /* Can only support bidirectional stream */
1146+ PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
1147+
1148+ if (id == 0) {
1149+ /* Initialize our stream data */
1150+ pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
1151+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
1152+
1153+ strm->pool = pool;
1154+ } else {
1155+ pool = strm->pool = streams[0].pool;
1156+ }
1157+
1158+ strm->rec_cb = rec_cb;
1159+ strm->play_cb = play_cb;
1160+ strm->user_data = user_data;
1161+
1162+ pj_memcpy(&strm->param, param, sizeof(*param));
1163+
1164+ if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
1165+ strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
1166+ }
1167+
1168+ strm->timestamp.u64 = 0;
1169+ strm->dev_ctx = &(af->dev_ctx);
1170+
1171+ /* Create and start the thread */
1172+ if (id == 1) {
1173+ status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, &streams[0].thread);
1174+ if (status != PJ_SUCCESS) {
1175+ stream_destroy(&strm->base);
1176+ return status;
1177+ }
1178+ }
1179+
1180+ /* Done */
1181+ strm->base.op = &tapi_strm_op;
1182+ *p_aud_strm = &strm->base;
1183+
1184+ return PJ_SUCCESS;
1185+}
1186+
1187+static pj_status_t
1188+stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
1189+{
1190+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1191+
1192+ PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1193+ pj_memcpy(pi, &strm->param, sizeof(*pi));
1194+
1195+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1196+ &pi->output_vol) == PJ_SUCCESS)
1197+ pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1198+
1199+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
1200+ &pi->output_latency_ms) == PJ_SUCCESS)
1201+ pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
1202+
1203+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
1204+ &pi->input_latency_ms) == PJ_SUCCESS)
1205+ pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1206+
1207+ return PJ_SUCCESS;
1208+}
1209+
1210+static pj_status_t
1211+stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
1212+{
1213+ // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1214+ return PJ_SUCCESS;
1215+}
1216+
1217+static pj_status_t
1218+stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
1219+{
1220+ // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1221+ return PJ_SUCCESS;
1222+}
1223+
1224+static pj_status_t
1225+stream_start(pjmedia_aud_stream *s)
1226+{
1227+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1228+ pj_uint32_t dev_idx;
1229+
1230+ TRACE_((THIS_FILE, "stream_start()"));
1231+
1232+ dev_idx = strm->param.rec_id;
1233+
1234+ return PJ_SUCCESS;
1235+}
1236+
1237+static pj_status_t
1238+stream_stop(pjmedia_aud_stream *s)
1239+{
1240+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1241+ tapi_ctx *dev_ctx = strm->dev_ctx;
1242+ pj_uint32_t dev_idx;
1243+
1244+ TRACE_((THIS_FILE, "stream_stop()"));
1245+ dev_idx = strm->param.rec_id;
1246+
1247+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
1248+ TRACE_((THIS_FILE, "ERROR - codec start failed!"));
1249+ return PJ_EUNKNOWN;
1250+ }
1251+
1252+ return PJ_SUCCESS;
1253+}
1254+
1255+static pj_status_t
1256+stream_destroy(pjmedia_aud_stream *s)
1257+{
1258+ pj_status_t state = PJ_SUCCESS;
1259+ struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
1260+ pj_pool_t *pool;
1261+
1262+ PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
1263+ TRACE_((THIS_FILE, "stream_destroy()"));
1264+
1265+ stream_stop(&stream->base);
1266+ stream->run_flag = 0;
1267+
1268+ if (stream->thread)
1269+ {
1270+ pj_thread_join(stream->thread);
1271+ pj_thread_destroy(stream->thread);
1272+ stream->thread = NULL;
1273+ }
1274+
1275+ pool = stream->pool;
1276+ pj_bzero(stream, sizeof(stream));
1277+ pj_pool_release(pool);
1278+
1279+ return state;
1280+}
1281+
1282+pj_status_t
1283+tapi_hook_status(pj_uint8_t port, pj_int32_t *status)
1284+{
1285+ PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1286+
1287+ if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
1288+ != PJ_SUCCESS) {
1289+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
1290+ return PJ_EUNKNOWN;
1291+ }
1292+
1293+ return PJ_SUCCESS;
1294+}
1295+
1296+pj_status_t
1297+tapi_ring(pj_uint8_t port, pj_uint8_t state, char *caller_number)
1298+{
1299+ PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1300+
1301+ if (state) {
1302+ if (tapi_cid_type && caller_number) {
1303+ IFX_TAPI_CID_MSG_t cid_msg;
1304+ IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
1305+ memset(&cid_msg, 0, sizeof(cid_msg));
1306+ memset(&cid_msg_el, 0, sizeof(cid_msg_el));
1307+
1308+ cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
1309+ cid_msg_el[0].string.len = strlen(caller_number);
1310+ strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
1311+
1312+ cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
1313+ cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
1314+ cid_msg.nMsgElements = 1;
1315+ cid_msg.message = cid_msg_el;
1316+ ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
1317+ } else {
1318+ ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
1319+ }
1320+ } else {
1321+ ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
1322+ }
1323+
1324+ return PJ_SUCCESS;
1325+}
1326+
1327+pj_status_t
1328+tapi_tone(pj_uint8_t port, pj_uint8_t code)
1329+{
1330+ PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1331+
1332+ if (tapi_locale && code)
1333+ ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, code);
1334+ else if (code)
1335+ ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, TAPI_TONE_LOCALE_NONE);
1336+ else
1337+ ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
1338+
1339+ return PJ_SUCCESS;
1340+}
1341+
1342+#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */
1343--
13441.7.7.1
1345
1346

Archive Download this file



interactive