pjsip: bump to 1.10 and improve ltq_tapi backend
[lede.git] / package / pjsip / src / pjmedia / src / pjmedia-audiodev / tapi_dev.c
1 /******************************************************************************
2
3                                Copyright (c) 2010
4                             Lantiq Deutschland GmbH
5                      Am Campeon 3; 85579 Neubiberg, Germany
6
7   For licensing information, see the file 'LICENSE' in the root folder of
8   this software module.
9
10 ******************************************************************************/
11 #include <pjmedia-audiodev/audiodev_imp.h>
12 #include <pjmedia/errno.h>
13 #include <pj/assert.h>
14 #include <pj/pool.h>
15 #include <pj/log.h>
16 #include <pj/os.h>
17
18 /* Linux includes */
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include <sys/stat.h> 
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/select.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 #include <poll.h>
31
32 #if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
33 /* TAPI includes */
34 #include "drv_tapi_io.h"
35 #include "vmmc_io.h"
36
37 /* Maximum 2 devices */
38 #define TAPI_AUDIO_PORT_NUM          (2)
39 #define TAPI_BASE_NAME              "TAPI"
40 #define TAPI_LL_DEV_BASE_PATH       "/dev/vmmc"
41 #define TAPI_LL_DEV_FIRMWARE_NAME   "/lib/firmware/danube_firmware.bin"
42 #define TAPI_LL_BBD_NAME   "/lib/firmware/danube_bbd_fxs.bin"
43
44 #define TAPI_LL_DEV_SELECT_TIMEOUT_MS      (2000)
45 #define TAPI_LL_DEV_MAX_PACKET_SIZE        (800)
46 #define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE   (12)
47 #define TAPI_LL_DEV_ENC_FRAME_LEN_MS       (20)
48 #define TAPI_LL_DEV_ENC_SMPL_PER_SEC       (8000)
49 #define TAPI_LL_DEV_ENC_BITS_PER_SMPLS     (16)
50 #define TAPI_LL_DEV_ENC_SMPL_PER_FRAME     (160)
51 #define TAPI_LL_DEV_ENC_BYTES_PER_FRAME    (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
52
53 #define THIS_FILE     "tapi_dev.c"
54
55 #if 1
56 #   define TRACE_(x)    PJ_LOG(1,x)
57 #else
58 #   define TRACE_(x)
59 #endif
60
61 pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
62
63 typedef struct
64 {
65         pj_int32_t dev_fd;
66         pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
67         pj_int8_t  data2phone_map[TAPI_AUDIO_PORT_NUM];
68 } tapi_ctx;
69
70 struct tapi_aud_factory
71 {
72         pjmedia_aud_dev_factory base;
73         pj_pool_t               *pool;
74         pj_pool_factory         *pf;
75         pj_uint32_t             dev_count;
76         pjmedia_aud_dev_info    *dev_info;
77         tapi_ctx                dev_ctx;
78 };
79
80 typedef struct tapi_aud_factory tapi_aud_factory_t;
81
82 struct tapi_aud_stream
83 {
84         pjmedia_aud_stream      base;
85         pj_pool_t               *pool;
86         pjmedia_aud_param       param;
87         pjmedia_aud_rec_cb      rec_cb;
88         pjmedia_aud_play_cb     play_cb;
89         void                    *user_data;
90
91         pj_thread_desc          thread_desc;
92         pj_thread_t             *thread;
93         tapi_ctx                *dev_ctx;
94         pj_uint8_t              run_flag;
95         pj_timestamp            timestamp;
96 };
97
98 typedef struct tapi_aud_stream tapi_aud_stream_t;
99
100 /* Factory prototypes */
101 static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
102 static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
103 static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
104 static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
105           unsigned index,
106           pjmedia_aud_dev_info *info);
107 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
108            unsigned index,
109            pjmedia_aud_param *param);
110 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
111            const pjmedia_aud_param *param,
112            pjmedia_aud_rec_cb rec_cb,
113            pjmedia_aud_play_cb play_cb,
114            void *user_data,
115            pjmedia_aud_stream **p_aud_strm);
116
117 /* Stream prototypes */
118 static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
119           pjmedia_aud_param *param);
120 static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
121               pjmedia_aud_dev_cap cap,
122               void *value);
123 static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
124               pjmedia_aud_dev_cap cap,
125               const void *value);
126 static pj_status_t stream_start(pjmedia_aud_stream *strm);
127 static pj_status_t stream_stop(pjmedia_aud_stream *strm);
128 static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
129
130 static pjmedia_aud_dev_factory_op tapi_fact_op =
131 {
132         &factory_init,
133         &factory_destroy,
134         &factory_get_dev_count,
135         &factory_get_dev_info,
136         &factory_default_param,
137         &factory_create_stream
138 };
139
140 static pjmedia_aud_stream_op tapi_strm_op =
141 {
142         &stream_get_param,
143         &stream_get_cap,
144         &stream_set_cap,
145         &stream_start,
146         &stream_stop,
147         &stream_destroy
148 };
149
150 void (*tapi_digit_callback)(unsigned int port, unsigned char digit) = NULL;
151 void (*tapi_hook_callback)(unsigned int port, unsigned char event) = NULL;
152
153 static pj_int32_t
154 tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
155 {
156         char devname[128] = {0};
157         pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
158         return open((const char*)devname, O_RDWR, 0644);
159 }
160
161 static pj_status_t
162 tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
163 {
164         pj_status_t status = PJ_SUCCESS;
165         FILE *fd;
166         struct stat file_stat;
167
168         fd = fopen(pPath, "rb");
169         if (fd == NULL) {
170                 TRACE_((THIS_FILE, "ERROR -  binary file %s open failed!\n", pPath));
171                 return PJ_EUNKNOWN;
172         }
173
174         if (stat(pPath, &file_stat) != 0) {
175                 TRACE_((THIS_FILE, "ERROR -  file %s statistics get failed!\n", pPath));
176                 return PJ_EUNKNOWN;
177         }
178
179         *ppBuf = malloc(file_stat.st_size);
180         if (*ppBuf == NULL) {
181                 TRACE_((THIS_FILE, "ERROR -  binary file %s memory allocation failed!\n", pPath));
182                 status = PJ_EUNKNOWN;
183                 goto on_exit;
184         }
185
186         if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
187                 TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
188                 status = PJ_EUNKNOWN;
189                 goto on_exit;
190         }
191
192         *pBufSz = file_stat.st_size;
193
194 on_exit:
195         if (fd != NULL)
196                 fclose(fd);
197
198         if (*ppBuf != NULL && status != PJ_SUCCESS)
199                 free(*ppBuf);
200
201         return status;
202 }
203
204 static void
205 tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
206 {
207         if (pBuf != NULL)
208                 free(pBuf);
209 }
210
211 static pj_status_t
212 tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
213 {
214         pj_status_t status = PJ_SUCCESS;
215         pj_uint8_t *pFirmware = NULL;
216         pj_uint32_t binSz = 0;
217         VMMC_IO_INIT vmmc_io_init;
218
219         status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
220         if (status != PJ_SUCCESS) {
221                 TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
222                 return PJ_EUNKNOWN;
223         }
224
225         memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
226         vmmc_io_init.pPRAMfw   = pFirmware;
227         vmmc_io_init.pram_size = binSz;
228
229         status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
230         if (status != PJ_SUCCESS)
231                 TRACE_((THIS_FILE, "ERROR -  FIO_FW_DOWNLOAD ioctl failed!"));
232
233         tapi_dev_binary_buffer_delete(pFirmware);
234
235         return status;
236 }
237
238 static int
239 tapi_dev_bbd_download(int fd, const char *pPath)
240 {
241         int status = PJ_SUCCESS;
242         unsigned char *pFirmware = NULL;
243         unsigned int binSz = 0;
244         VMMC_DWLD_t bbd_data;
245
246
247         /* Create binary buffer */
248         status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
249         if (status != PJ_SUCCESS) {
250                 TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
251                 return status;
252         }
253
254         /* Download Voice Firmware */
255         memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
256         bbd_data.buf = pFirmware;
257         bbd_data.size = binSz;
258
259         status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
260         if (status != PJ_SUCCESS) {
261                 TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
262         }
263
264         /* Delete binary buffer */
265         tapi_dev_binary_buffer_delete(pFirmware);
266
267         return status;
268 }
269
270 static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
271 {
272         pj_uint8_t c, hook_status;
273         pj_status_t status = PJ_SUCCESS;
274         IFX_TAPI_DEV_START_CFG_t tapistart;
275         IFX_TAPI_MAP_DATA_t datamap;
276         IFX_TAPI_ENC_CFG_t enc_cfg;
277         IFX_TAPI_LINE_VOLUME_t line_vol;
278         IFX_TAPI_CID_CFG_t cid_cnf;
279         
280         /* Open device */
281         f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
282         
283         if (f->dev_ctx.dev_fd < 0) {
284                 TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
285                 return PJ_EUNKNOWN;
286         }
287
288         for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
289                 ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
290
291                 if (f->dev_ctx.dev_fd < 0) {
292                         TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
293                         return PJ_EUNKNOWN;
294                 }
295                 f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
296         }
297
298         status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
299         if (status != PJ_SUCCESS) {
300                 TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
301                 return PJ_EUNKNOWN;
302         }
303
304         /* Download coefficients */
305         /*
306         status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
307         if (status != PJ_SUCCESS) {
308                 TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
309                 return PJ_EUNKNOWN;
310         }
311         */
312
313         memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
314         tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
315         
316         /* Start TAPI */
317         status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
318         if (status != PJ_SUCCESS) {
319                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
320                 return PJ_EUNKNOWN;
321         }
322
323
324         for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
325                 /* Perform mapping */
326                 memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
327                 datamap.nDstCh  = f->dev_ctx.data2phone_map[c];
328                 datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
329                 
330                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
331                 
332                 if (status != PJ_SUCCESS) {
333                         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
334                         return PJ_EUNKNOWN;
335                 }
336                 
337                 /* Set Line feed */
338                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
339                 
340                 if (status != PJ_SUCCESS) {
341                         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
342                         return PJ_EUNKNOWN;
343                 }
344                 
345                 /* Configure encoder for linear stream */
346                 memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
347                 
348                 enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
349                 enc_cfg.nEncType  = IFX_TAPI_COD_TYPE_LIN16_8;
350                 
351                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
352                 if (status != PJ_SUCCESS) {
353                         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
354                         return PJ_EUNKNOWN;
355                 }
356                 
357                 /* Suppress TAPI volume, otherwise PJSIP starts autogeneration!!! */
358                 line_vol.nGainRx = -8;
359                 line_vol.nGainTx = -8;
360                 
361                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
362                 if (status != PJ_SUCCESS) {
363                         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
364                         return PJ_EUNKNOWN;
365                 }
366                 
367                 /* Configure Caller ID type */
368                 /* One can choose from following (for now at compile time):
369                         IFX_TAPI_CID_STD_TELCORDIA
370                         IFX_TAPI_CID_STD_ETSI_FSK
371                         IFX_TAPI_CID_STD_ETSI_DTMF
372                         IFX_TAPI_CID_STD_SIN
373                         IFX_TAPI_CID_STD_NTT
374                         IFX_TAPI_CID_STD_KPN_DTMF
375                         IFX_TAPI_CID_STD_KPN_DTMF_FSK
376                 */
377                 memset(&cid_cnf, 0, sizeof(cid_cnf));
378                 cid_cnf.nStandard = IFX_TAPI_CID_STD_ETSI_FSK;
379                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cnf);
380                 if (status != PJ_SUCCESS) {
381                         TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
382                         return PJ_EUNKNOWN;
383                 }
384                 
385                 /* check hook status */
386                 hook_status = 0;
387                 status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
388                 if (status != PJ_SUCCESS) {
389                    TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
390                    return PJ_EUNKNOWN;
391                 }
392                 
393                 /* if off hook do initialization */
394                 if (hook_status) {
395                         status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
396                         if (status != PJ_SUCCESS) {
397                                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
398                                 return PJ_EUNKNOWN;
399                         }
400                         status = ioctl(c, IFX_TAPI_ENC_START, 0);
401                         if (status != PJ_SUCCESS) {
402                                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
403                                 return PJ_EUNKNOWN;
404                         }
405
406                         status = ioctl(c, IFX_TAPI_DEC_START, 0);
407                         if (status != PJ_SUCCESS) {
408                                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
409                                 return PJ_EUNKNOWN;
410                         }
411                 }
412         }
413
414         return status;
415 }
416
417 static pj_status_t
418 tapi_dev_stop(tapi_aud_factory_t *f)
419 {
420         pj_status_t status = PJ_SUCCESS;
421         pj_uint8_t c;
422
423         if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
424                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
425                 status = PJ_EUNKNOWN;
426         }
427
428         close(f->dev_ctx.dev_fd);
429         for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
430                 close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
431
432         return status;
433 }
434
435 static pj_status_t
436 tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
437 {
438         if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
439                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
440                         start ? "START" : "STOP"));
441                 return PJ_EUNKNOWN;
442         }
443
444         if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
445                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
446                         start ? "START" : "STOP"));
447                 return PJ_EUNKNOWN;
448         }
449
450         return PJ_SUCCESS;
451 }
452
453 static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
454 {
455    PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
456
457    if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
458                IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
459       TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
460
461       return PJ_EUNKNOWN;
462    }
463
464    /* enc/dec stop */
465    if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
466       TRACE_((THIS_FILE, "ERROR - codec start failed!"));
467
468       return PJ_EUNKNOWN;
469    }
470
471    return PJ_SUCCESS;
472 }
473
474 static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
475 {
476    PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
477
478    if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
479                IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
480       TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
481
482       return PJ_EUNKNOWN;
483    }
484
485    /* enc/dec stop */
486    if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
487       TRACE_((THIS_FILE, "ERROR - codec start failed!"));
488
489       return PJ_EUNKNOWN;
490    }
491
492    return PJ_SUCCESS;
493 }
494
495 static pj_status_t
496 tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
497 {
498         PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
499
500         if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
501                         IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
502                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
503                 return PJ_EUNKNOWN;
504         }
505
506         /* enc/dec stop */
507         if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
508                 TRACE_((THIS_FILE, "ERROR - codec start failed!"));
509                 return PJ_EUNKNOWN;
510         }
511
512         return PJ_SUCCESS;
513 }
514
515 static pj_status_t
516 tapi_dev_event_handler(tapi_aud_stream_t *stream)
517 {
518         IFX_TAPI_EVENT_t tapiEvent;
519         tapi_ctx *dev_ctx = stream->dev_ctx;
520         pj_status_t status = PJ_SUCCESS;
521         unsigned int i;
522
523         for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
524                 memset (&tapiEvent, 0, sizeof(tapiEvent));
525                 tapiEvent.ch = dev_ctx->data2phone_map[i];
526                 status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
527
528                 if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
529                         switch(tapiEvent.id) {
530                         case IFX_TAPI_EVENT_FXS_ONHOOK:
531                                 status = tapi_dev_event_on_hook(dev_ctx, i);
532                                 if(tapi_hook_callback)
533                                         tapi_hook_callback(i, 0);
534                                 break;
535                         case IFX_TAPI_EVENT_FXS_OFFHOOK:
536                                 status = tapi_dev_event_off_hook(dev_ctx, i);
537                                 if(tapi_hook_callback)
538                                         tapi_hook_callback(i, 1);
539                                 break;
540                         case IFX_TAPI_EVENT_DTMF_DIGIT:
541                                 if(tapi_digit_callback)
542                                         tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
543                                 break;
544                         case IFX_TAPI_EVENT_COD_DEC_CHG:
545                         case IFX_TAPI_EVENT_TONE_GEN_END:
546                         case IFX_TAPI_EVENT_CID_TX_SEQ_END:
547                                 break;
548                         default:
549                                 PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
550                                 break;
551                         }
552                 }
553         }
554
555         return status;
556 }
557
558 static pj_status_t
559 tapi_dev_data_handler(tapi_aud_stream_t *stream) {
560    pj_status_t status = PJ_SUCCESS;
561    tapi_ctx *dev_ctx = stream->dev_ctx;
562    pj_uint32_t dev_idx = stream->param.rec_id;
563    pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
564    pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
565    pjmedia_frame frame_rec, frame_play;
566    pj_int32_t ret;
567
568    /* Get data from driver */
569    ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
570    if (ret < 0) {
571       TRACE_((THIS_FILE, "ERROR - no data available from device!"));
572
573       return PJ_EUNKNOWN;
574    }
575
576    if (ret > 0) {
577       frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
578       frame_rec.buf  = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
579       frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
580       frame_rec.timestamp.u64 = stream->timestamp.u64;
581
582       status = stream->rec_cb(stream->user_data, &frame_rec);
583       if (status != PJ_SUCCESS)
584       {
585         PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
586       }
587
588       frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
589       frame_play.buf  = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
590       frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
591       frame_play.timestamp.u64 = stream->timestamp.u64;
592
593       status = (*stream->play_cb)(stream->user_data, &frame_play);
594       if (status != PJ_SUCCESS)
595       {
596          PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
597       }
598       else
599       {
600          memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
601
602          ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
603
604          if (ret < 0) {
605             PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
606             return PJ_EUNKNOWN;
607          }
608
609          if (ret == 0) {
610             PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
611             return PJ_EUNKNOWN;
612          }
613       }
614
615       stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
616    }
617
618    return PJ_SUCCESS;
619 }
620
621 static int
622 PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
623         tapi_aud_stream_t *strm = (struct tapi_aud_stream*)arg;
624         tapi_ctx *dev_ctx = strm->dev_ctx;
625         pj_uint32_t sretval;
626         pj_uint32_t dev_idx;
627         struct pollfd fds[3];
628
629         PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
630
631         if (strm->param.rec_id != strm->param.play_id) {
632                 PJ_LOG(1,(THIS_FILE, "TAPI: thread exit - incorrect play/rec IDs"));
633                 return 0;
634         }
635
636         dev_idx = strm->param.rec_id;
637         strm->run_flag = 1;
638
639         fds[0].fd = dev_ctx->dev_fd;
640         fds[0].events = POLLIN;
641         fds[1].fd = dev_ctx->ch_fd[0];
642         fds[1].events = POLLIN;
643         fds[2].fd = dev_ctx->ch_fd[1];
644         fds[2].events = POLLIN;
645
646         while(1)
647         {
648                 sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
649
650                 if (!strm->run_flag)
651                         break;
652                 if (sretval <= 0)
653                         continue;
654
655                 if (fds[0].revents == POLLIN) {
656                         if (tapi_dev_event_handler(strm) != PJ_SUCCESS) {
657                                 PJ_LOG(1,(THIS_FILE, "TAPI: event hanldler failed!"));
658                                 break;
659                         }
660                 }
661
662                 if (fds[1].revents == POLLIN) {
663                         if (tapi_dev_data_handler(strm) != PJ_SUCCESS) {
664                                 PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!"));
665                                 break;
666                         }
667                 }
668
669                 if (fds[2].revents == POLLIN) {
670                         if (tapi_dev_data_handler(strm) != PJ_SUCCESS) {
671                                 PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!"));
672                                 break;
673                         }
674                 }
675         }
676         PJ_LOG(1,(THIS_FILE, "TAPI: thread stopping..."));
677
678         return 0;
679 }
680
681 /****************************************************************************
682  Factory operations
683  ****************************************************************************/
684
685 pjmedia_aud_dev_factory*
686 pjmedia_tapi_factory(pj_pool_factory *pf) {
687         struct tapi_aud_factory *f;
688         pj_pool_t *pool;
689
690         TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
691
692         pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
693         f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
694         f->pf = pf;
695         f->pool = pool;
696         f->base.op = &tapi_fact_op;
697
698         return &f->base;
699 }
700
701 static pj_status_t
702 factory_init(pjmedia_aud_dev_factory *f)
703 {
704         struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
705         pj_uint8_t c;
706
707         TRACE_((THIS_FILE, "factory_init()"));
708
709         af->dev_count = 1;
710         af->dev_info = (pjmedia_aud_dev_info*)
711         pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
712         pj_ansi_sprintf(af->dev_info[0].name,"%s_%02d", TAPI_BASE_NAME, c);
713         af->dev_info[0].input_count = af->dev_info[0].output_count = TAPI_AUDIO_PORT_NUM;
714         af->dev_info[0].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
715         pj_ansi_strcpy(af->dev_info[0].driver, "/dev/vmmc");
716         af->dev_info[0].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
717                 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
718                 PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
719         af->dev_info[0].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
720         if (tapi_dev_start(af) != PJ_SUCCESS) {
721                 TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
722                 return PJ_EUNKNOWN;
723         }
724
725         return PJ_SUCCESS;
726 }
727
728 static pj_status_t
729 factory_destroy(pjmedia_aud_dev_factory *f)
730 {
731         struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
732         pj_pool_t *pool;
733         pj_status_t status = PJ_SUCCESS;
734
735         TRACE_((THIS_FILE, "factory_destroy()"));
736
737         if (tapi_dev_stop(f) != PJ_SUCCESS) {
738                 TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
739                 status = PJ_EUNKNOWN;
740         }
741         pool = af->pool;
742         af->pool = NULL;
743         pj_pool_release(pool);
744
745         return status;
746 }
747
748 static unsigned
749 factory_get_dev_count(pjmedia_aud_dev_factory *f)
750 {
751         struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
752         TRACE_((THIS_FILE, "factory_get_dev_count()"));
753
754         return af->dev_count;
755 }
756
757 static pj_status_t
758 factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
759 {
760         struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
761
762         TRACE_((THIS_FILE, "factory_get_dev_info()"));
763         PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
764
765         pj_memcpy(info, &af->dev_info[index], sizeof(*info));
766
767         return PJ_SUCCESS;
768 }
769
770 static pj_status_t
771 factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
772 {
773         struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
774         struct pjmedia_aud_dev_info *di = &af->dev_info[index];
775
776         TRACE_((THIS_FILE, "factory_default_param."));
777         PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
778
779         pj_bzero(param, sizeof(*param));
780         if (di->input_count && di->output_count) {
781                 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
782                 param->rec_id = index;
783                 param->play_id = index;
784         } else if (di->input_count) {
785                 param->dir = PJMEDIA_DIR_CAPTURE;
786                 param->rec_id = index;
787                 param->play_id = PJMEDIA_AUD_INVALID_DEV;
788         } else if (di->output_count) {
789                 param->dir = PJMEDIA_DIR_PLAYBACK;
790                 param->play_id = index;
791                 param->rec_id = PJMEDIA_AUD_INVALID_DEV;
792         } else {
793                 return PJMEDIA_EAUD_INVDEV;
794         }
795
796         param->clock_rate = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
797         param->channel_count = 1;
798         param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
799         param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
800         param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
801         param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
802
803         return PJ_SUCCESS;
804 }
805
806 static pj_status_t
807 factory_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param,
808         pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb,
809         void *user_data, pjmedia_aud_stream **p_aud_strm)
810 {
811    struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
812    pj_pool_t *pool;
813    struct tapi_aud_stream *strm;
814    pj_status_t status;
815
816    TRACE_((THIS_FILE, "factory_create_stream()"));
817
818    /* Can only support 16bits per sample */
819    PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
820    printf("param->clock_rate = %d, samples_per_frame = %d\n", param->clock_rate, param->samples_per_frame);
821    PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
822
823    PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
824
825    /* Can only support bidirectional stream */
826    PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
827
828    /* Initialize our stream data */
829    pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
830    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
831
832    strm = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_stream);
833    strm->pool      = pool;
834    strm->rec_cb    = rec_cb;
835    strm->play_cb   = play_cb;
836    strm->user_data = user_data;
837    pj_memcpy(&strm->param, param, sizeof(*param));
838
839    if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
840       strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
841    }
842
843    strm->timestamp.u64 = 0;
844    strm->dev_ctx = &(af->dev_ctx);
845
846    /* Create and start the thread */
847    status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, 
848                               &strm->thread);
849    if (status != PJ_SUCCESS) {
850       stream_destroy(&strm->base);
851       return status;
852    }
853
854    /* Done */
855    strm->base.op = &tapi_strm_op;
856    *p_aud_strm = &strm->base;
857
858    return PJ_SUCCESS;
859 }
860
861 static pj_status_t
862 stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
863 {
864         struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
865
866         PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
867         pj_memcpy(pi, &strm->param, sizeof(*pi));
868
869         if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
870                         &pi->output_vol) == PJ_SUCCESS)
871                 pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
872
873         if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
874                         &pi->output_latency_ms) == PJ_SUCCESS)
875                 pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
876
877         if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
878                         &pi->input_latency_ms) == PJ_SUCCESS)
879                 pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
880
881         return PJ_SUCCESS;
882 }
883
884 static pj_status_t
885 stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
886 {
887         // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
888         return PJ_SUCCESS;
889 }
890
891 static pj_status_t
892 stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
893 {
894         // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
895         return PJ_SUCCESS;
896 }
897
898 static pj_status_t
899 stream_start(pjmedia_aud_stream *s)
900 {
901         struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
902         tapi_ctx *dev_ctx = strm->dev_ctx;
903         pj_uint32_t dev_idx;
904
905         TRACE_((THIS_FILE, "stream_start()"));
906
907         dev_idx = strm->param.rec_id;
908
909         return PJ_SUCCESS;
910 }
911
912 static pj_status_t
913 stream_stop(pjmedia_aud_stream *s)
914 {
915         struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
916         tapi_ctx *dev_ctx = strm->dev_ctx;
917         pj_uint32_t dev_idx;
918
919         TRACE_((THIS_FILE, "stream_stop()"));
920         dev_idx = strm->param.rec_id;
921
922         if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
923                 TRACE_((THIS_FILE, "ERROR - codec start failed!"));
924                 return PJ_EUNKNOWN;
925         }
926
927         return PJ_SUCCESS;
928 }
929
930 static pj_status_t
931 stream_destroy(pjmedia_aud_stream *s)
932 {
933         pj_status_t state = PJ_SUCCESS;
934         struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
935         pj_pool_t *pool;
936
937         PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
938         TRACE_((THIS_FILE, "stream_destroy()"));
939
940         stream_stop(stream);
941         stream->run_flag = 0;
942
943         if (stream->thread)
944         {
945                 pj_thread_join(stream->thread);
946                 pj_thread_destroy(stream->thread);
947                 stream->thread = NULL;
948         }
949
950         pool = stream->pool;
951         pj_bzero(stream, sizeof(stream));
952         pj_pool_release(pool);
953
954         return state;
955 }
956
957 pj_status_t
958 tapi_hook_status(pj_uint32_t port, pj_uint32_t *status)
959 {
960         if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
961                         != PJ_SUCCESS) {
962                 TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
963                 return PJ_EUNKNOWN;
964         }
965                 
966         return PJ_SUCCESS;
967 }
968
969 pj_status_t
970 tapi_ring(pj_uint32_t port, pj_uint32_t state, char *caller_number) {
971         PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
972
973         if (state) {
974                 if (caller_number) {
975                         IFX_TAPI_CID_MSG_t cid_msg;
976                         IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
977                         memset(&cid_msg, 0, sizeof(cid_msg));
978                         memset(&cid_msg_el, 0, sizeof(cid_msg_el));
979
980                         cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
981                         cid_msg_el[0].string.len = strlen(caller_number);
982                         strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
983
984                         cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
985                         cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
986                         cid_msg.nMsgElements = 1;
987                         cid_msg.message = cid_msg_el;
988                         ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
989                 } else {
990                         ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
991                 }
992         } else {
993                 ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
994         }
995
996         return PJ_SUCCESS;
997 }
998
999 pj_status_t
1000 tapi_dial_tone(pj_uint32_t port) {
1001         PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1002
1003         ioctl(ch_fd[port], IFX_TAPI_TONE_DIALTONE_PLAY, 0);
1004
1005         return PJ_SUCCESS;
1006 }
1007
1008 pj_status_t
1009 tapi_no_tone(pj_uint32_t port) {
1010         PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1011
1012         ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
1013
1014         return PJ_SUCCESS;
1015 }
1016
1017 #endif