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

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

Archive Download this file



interactive