[lantiq] fix maintainer flag
[openwrt.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 */