pjsip: update to version 1.14.2
[openwrt/svn-archive/archive.git] / 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 */