[pjsip] Pulse dialing support into pjsip.
[openwrt/svn-archive/archive.git] / package / pjsip / patches / 0002-register-tapi.patch
1 From 455f6f2234a36aeeb97d3e05e9cbe3afad147341 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Sat, 28 Jan 2012 21:43:49 +0100
4 Subject: [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
12 diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
13 index 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) {
37 diff --git a/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
38 new file mode 100644
39 index 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 --
1344 1.7.7.1
1345