1 /******************************************************************************
4 Lantiq Deutschland GmbH
5 Am Campeon 3; 85579 Neubiberg, Germany
7 For licensing information, see the file 'LICENSE' in the root folder of
10 ******************************************************************************/
11 #include <pjmedia-audiodev/audiodev_imp.h>
12 #include <pjmedia/errno.h>
13 #include <pj/assert.h>
25 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/select.h>
32 #if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
34 #include "drv_tapi_io.h"
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"
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))
53 #define THIS_FILE "tapi_dev.c"
56 # define TRACE_(x) PJ_LOG(1,x)
61 pj_int32_t ch_fd
[TAPI_AUDIO_PORT_NUM
];
66 pj_int32_t ch_fd
[TAPI_AUDIO_PORT_NUM
];
67 pj_int8_t data2phone_map
[TAPI_AUDIO_PORT_NUM
];
70 struct tapi_aud_factory
72 pjmedia_aud_dev_factory base
;
75 pj_uint32_t dev_count
;
76 pjmedia_aud_dev_info
*dev_info
;
80 typedef struct tapi_aud_factory tapi_aud_factory_t
;
82 struct tapi_aud_stream
84 pjmedia_aud_stream base
;
86 pjmedia_aud_param param
;
87 pjmedia_aud_rec_cb rec_cb
;
88 pjmedia_aud_play_cb play_cb
;
91 pj_thread_desc thread_desc
;
95 pj_timestamp timestamp
;
98 typedef struct tapi_aud_stream tapi_aud_stream_t
;
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
,
106 pjmedia_aud_dev_info
*info
);
107 static pj_status_t
factory_default_param(pjmedia_aud_dev_factory
*f
,
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
,
115 pjmedia_aud_stream
**p_aud_strm
);
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
,
123 static pj_status_t
stream_set_cap(pjmedia_aud_stream
*strm
,
124 pjmedia_aud_dev_cap cap
,
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
);
130 static pjmedia_aud_dev_factory_op tapi_fact_op
=
134 &factory_get_dev_count
,
135 &factory_get_dev_info
,
136 &factory_default_param
,
137 &factory_create_stream
140 static pjmedia_aud_stream_op tapi_strm_op
=
150 void (*tapi_digit_callback
)(unsigned int port
, unsigned char digit
) = NULL
;
151 void (*tapi_hook_callback
)(unsigned int port
, unsigned char event
) = NULL
;
154 tapi_dev_open(char* dev_path
, const pj_int32_t ch_num
)
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);
162 tapi_dev_binary_buffer_create(const char *pPath
, pj_uint8_t
**ppBuf
, pj_uint32_t
*pBufSz
)
164 pj_status_t status
= PJ_SUCCESS
;
166 struct stat file_stat
;
168 fd
= fopen(pPath
, "rb");
170 TRACE_((THIS_FILE
, "ERROR - binary file %s open failed!\n", pPath
));
174 if (stat(pPath
, &file_stat
) != 0) {
175 TRACE_((THIS_FILE
, "ERROR - file %s statistics get failed!\n", pPath
));
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
;
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
;
192 *pBufSz
= file_stat
.st_size
;
198 if (*ppBuf
!= NULL
&& status
!= PJ_SUCCESS
)
205 tapi_dev_binary_buffer_delete(pj_uint8_t
*pBuf
)
212 tapi_dev_firmware_download(pj_int32_t fd
, const char *pPath
)
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
;
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"));
225 memset(&vmmc_io_init
, 0, sizeof(VMMC_IO_INIT
));
226 vmmc_io_init
.pPRAMfw
= pFirmware
;
227 vmmc_io_init
.pram_size
= binSz
;
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!"));
233 tapi_dev_binary_buffer_delete(pFirmware
);
239 tapi_dev_bbd_download(int fd
, const char *pPath
)
241 int status
= PJ_SUCCESS
;
242 unsigned char *pFirmware
= NULL
;
243 unsigned int binSz
= 0;
244 VMMC_DWLD_t bbd_data
;
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"));
254 /* Download Voice Firmware */
255 memset(&bbd_data
, 0, sizeof(VMMC_DWLD_t
));
256 bbd_data
.buf
= pFirmware
;
257 bbd_data
.size
= binSz
;
259 status
= ioctl(fd
, FIO_BBD_DOWNLOAD
, &bbd_data
);
260 if (status
!= PJ_SUCCESS
) {
261 TRACE_((THIS_FILE
, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
264 /* Delete binary buffer */
265 tapi_dev_binary_buffer_delete(pFirmware
);
270 static pj_status_t
tapi_dev_start(tapi_aud_factory_t
*f
)
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
;
281 f
->dev_ctx
.dev_fd
= tapi_dev_open(TAPI_LL_DEV_BASE_PATH
, 0);
283 if (f
->dev_ctx
.dev_fd
< 0) {
284 TRACE_((THIS_FILE
, "ERROR - TAPI device open failed!"));
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
);
291 if (f
->dev_ctx
.dev_fd
< 0) {
292 TRACE_((THIS_FILE
, "ERROR - TAPI channel%d open failed!", c
));
295 f
->dev_ctx
.data2phone_map
[c
] = c
& 0x1 ? 0 : 1;
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!"));
304 /* Download coefficients */
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!"));
313 memset(&tapistart
, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t
));
314 tapistart
.nMode
= IFX_TAPI_INIT_MODE_VOICE_CODER
;
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"));
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
;
330 status
= ioctl(f
->dev_ctx
.ch_fd
[c
], IFX_TAPI_MAP_DATA_ADD
, &datamap
);
332 if (status
!= PJ_SUCCESS
) {
333 TRACE_((THIS_FILE
, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
338 status
= ioctl(f
->dev_ctx
.ch_fd
[c
], IFX_TAPI_LINE_FEED_SET
, IFX_TAPI_LINE_FEED_STANDBY
);
340 if (status
!= PJ_SUCCESS
) {
341 TRACE_((THIS_FILE
, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
345 /* Configure encoder for linear stream */
346 memset(&enc_cfg
, 0x0, sizeof(IFX_TAPI_ENC_CFG_t
));
348 enc_cfg
.nFrameLen
= IFX_TAPI_COD_LENGTH_20
;
349 enc_cfg
.nEncType
= IFX_TAPI_COD_TYPE_LIN16_8
;
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"));
357 /* Suppress TAPI volume, otherwise PJSIP starts autogeneration!!! */
358 line_vol
.nGainRx
= -8;
359 line_vol
.nGainTx
= -8;
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"));
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
374 IFX_TAPI_CID_STD_KPN_DTMF
375 IFX_TAPI_CID_STD_KPN_DTMF_FSK
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"));
385 /* check hook status */
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!"));
393 /* if off hook do initialization */
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!"));
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!"));
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!"));
418 tapi_dev_stop(tapi_aud_factory_t
*f
)
420 pj_status_t status
= PJ_SUCCESS
;
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
;
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
]);
436 tapi_dev_codec_control(pj_int32_t fd
, pj_uint8_t start
)
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"));
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"));
453 static pj_status_t
tapi_dev_event_on_hook(tapi_ctx
*dev_ctx
, pj_uint32_t dev_idx
)
455 PJ_LOG(1,(THIS_FILE
, "TAPI: ONHOOK"));
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!"));
465 if (tapi_dev_codec_control(dev_ctx
->ch_fd
[dev_idx
], 0) != PJ_SUCCESS
) {
466 TRACE_((THIS_FILE
, "ERROR - codec start failed!"));
474 static pj_status_t
tapi_dev_event_off_hook(tapi_ctx
*dev_ctx
, pj_uint32_t dev_idx
)
476 PJ_LOG(1,(THIS_FILE
, "TAPI: OFFHOOK"));
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!"));
486 if (tapi_dev_codec_control(dev_ctx
->ch_fd
[dev_idx
], 1) != PJ_SUCCESS
) {
487 TRACE_((THIS_FILE
, "ERROR - codec start failed!"));
496 tapi_dev_event_digit(tapi_ctx
*dev_ctx
, pj_uint32_t dev_idx
)
498 PJ_LOG(1,(THIS_FILE
, "TAPI: OFFHOOK"));
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!"));
507 if (tapi_dev_codec_control(dev_ctx
->ch_fd
[dev_idx
], 1) != PJ_SUCCESS
) {
508 TRACE_((THIS_FILE
, "ERROR - codec start failed!"));
516 tapi_dev_event_handler(tapi_aud_stream_t
*stream
)
518 IFX_TAPI_EVENT_t tapiEvent
;
519 tapi_ctx
*dev_ctx
= stream
->dev_ctx
;
520 pj_status_t status
= PJ_SUCCESS
;
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
);
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);
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);
540 case IFX_TAPI_EVENT_DTMF_DIGIT
:
541 if(tapi_digit_callback
)
542 tapi_digit_callback(i
, tapiEvent
.data
.dtmf
.ascii
);
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
:
549 PJ_LOG(1,(THIS_FILE
, "unknown tapi event %08X", tapiEvent
.id
));
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
;
568 /* Get data from driver */
569 ret
= read(dev_ctx
->ch_fd
[dev_idx
], buf_rec
, sizeof(buf_rec
));
571 TRACE_((THIS_FILE
, "ERROR - no data available from device!"));
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
;
582 status
= stream
->rec_cb(stream
->user_data
, &frame_rec
);
583 if (status
!= PJ_SUCCESS
)
585 PJ_LOG(1, (THIS_FILE
, "rec_cb() failed %d", status
));
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
;
593 status
= (*stream
->play_cb
)(stream
->user_data
, &frame_play
);
594 if (status
!= PJ_SUCCESS
)
596 PJ_LOG(1, (THIS_FILE
, "play_cb() failed %d", status
));
600 memcpy(buf_play
, buf_rec
, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE
);
602 ret
= write(dev_ctx
->ch_fd
[dev_idx
], buf_play
, sizeof(buf_play
));
605 PJ_LOG(1, (THIS_FILE
, "ERROR - device data writing failed!"));
610 PJ_LOG(1, (THIS_FILE
, "ERROR - no data written to device!"));
615 stream
->timestamp
.u64
+= TAPI_LL_DEV_ENC_SMPL_PER_FRAME
;
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
;
627 struct pollfd fds
[3];
629 PJ_LOG(1,(THIS_FILE
, "TAPI: thread starting..."));
631 if (strm
->param
.rec_id
!= strm
->param
.play_id
) {
632 PJ_LOG(1,(THIS_FILE
, "TAPI: thread exit - incorrect play/rec IDs"));
636 dev_idx
= strm
->param
.rec_id
;
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
;
648 sretval
= poll(fds
, TAPI_AUDIO_PORT_NUM
+ 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS
);
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!"));
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!"));
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!"));
676 PJ_LOG(1,(THIS_FILE
, "TAPI: thread stopping..."));
681 /****************************************************************************
683 ****************************************************************************/
685 pjmedia_aud_dev_factory
*
686 pjmedia_tapi_factory(pj_pool_factory
*pf
) {
687 struct tapi_aud_factory
*f
;
690 TRACE_((THIS_FILE
, "pjmedia_tapi_factory()"));
692 pool
= pj_pool_create(pf
, "tapi", 512, 512, NULL
);
693 f
= PJ_POOL_ZALLOC_T(pool
, struct tapi_aud_factory
);
696 f
->base
.op
= &tapi_fact_op
;
702 factory_init(pjmedia_aud_dev_factory
*f
)
704 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
707 TRACE_((THIS_FILE
, "factory_init()"));
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!"));
729 factory_destroy(pjmedia_aud_dev_factory
*f
)
731 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
733 pj_status_t status
= PJ_SUCCESS
;
735 TRACE_((THIS_FILE
, "factory_destroy()"));
737 if (tapi_dev_stop(f
) != PJ_SUCCESS
) {
738 TRACE_((THIS_FILE
, "ERROR - TAPI device stop failed!"));
739 status
= PJ_EUNKNOWN
;
743 pj_pool_release(pool
);
749 factory_get_dev_count(pjmedia_aud_dev_factory
*f
)
751 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
752 TRACE_((THIS_FILE
, "factory_get_dev_count()"));
754 return af
->dev_count
;
758 factory_get_dev_info(pjmedia_aud_dev_factory
*f
, unsigned index
, pjmedia_aud_dev_info
*info
)
760 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
762 TRACE_((THIS_FILE
, "factory_get_dev_info()"));
763 PJ_ASSERT_RETURN(index
< af
->dev_count
, PJMEDIA_EAUD_INVDEV
);
765 pj_memcpy(info
, &af
->dev_info
[index
], sizeof(*info
));
771 factory_default_param(pjmedia_aud_dev_factory
*f
, unsigned index
, pjmedia_aud_param
*param
)
773 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
774 struct pjmedia_aud_dev_info
*di
= &af
->dev_info
[index
];
776 TRACE_((THIS_FILE
, "factory_default_param."));
777 PJ_ASSERT_RETURN(index
< af
->dev_count
, PJMEDIA_EAUD_INVDEV
);
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
;
793 return PJMEDIA_EAUD_INVDEV
;
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
;
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
)
811 struct tapi_aud_factory
*af
= (struct tapi_aud_factory
*)f
;
813 struct tapi_aud_stream
*strm
;
816 TRACE_((THIS_FILE
, "factory_create_stream()"));
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
);
823 PJ_ASSERT_RETURN(param
->samples_per_frame
== TAPI_LL_DEV_ENC_SMPL_PER_FRAME
, PJ_EINVAL
);
825 /* Can only support bidirectional stream */
826 PJ_ASSERT_RETURN(param
->dir
& PJMEDIA_DIR_CAPTURE_PLAYBACK
, PJ_EINVAL
);
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
);
832 strm
= PJ_POOL_ZALLOC_T(pool
, struct tapi_aud_stream
);
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
));
839 if ((strm
->param
.flags
& PJMEDIA_AUD_DEV_CAP_EXT_FORMAT
) == 0) {
840 strm
->param
.ext_fmt
.id
= PJMEDIA_FORMAT_L16
;
843 strm
->timestamp
.u64
= 0;
844 strm
->dev_ctx
= &(af
->dev_ctx
);
846 /* Create and start the thread */
847 status
= pj_thread_create(pool
, "tapi", &tapi_dev_thread
, strm
, 0, 0,
849 if (status
!= PJ_SUCCESS
) {
850 stream_destroy(&strm
->base
);
855 strm
->base
.op
= &tapi_strm_op
;
856 *p_aud_strm
= &strm
->base
;
862 stream_get_param(pjmedia_aud_stream
*s
, pjmedia_aud_param
*pi
)
864 struct tapi_aud_stream
*strm
= (struct tapi_aud_stream
*)s
;
866 PJ_ASSERT_RETURN(strm
&& pi
, PJ_EINVAL
);
867 pj_memcpy(pi
, &strm
->param
, sizeof(*pi
));
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
;
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
;
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
;
885 stream_get_cap(pjmedia_aud_stream
*s
, pjmedia_aud_dev_cap cap
, void *pval
)
887 // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
892 stream_set_cap(pjmedia_aud_stream
*s
, pjmedia_aud_dev_cap cap
, const void *pval
)
894 // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
899 stream_start(pjmedia_aud_stream
*s
)
901 struct tapi_aud_stream
*strm
= (struct tapi_aud_stream
*)s
;
902 tapi_ctx
*dev_ctx
= strm
->dev_ctx
;
905 TRACE_((THIS_FILE
, "stream_start()"));
907 dev_idx
= strm
->param
.rec_id
;
913 stream_stop(pjmedia_aud_stream
*s
)
915 struct tapi_aud_stream
*strm
= (struct tapi_aud_stream
*)s
;
916 tapi_ctx
*dev_ctx
= strm
->dev_ctx
;
919 TRACE_((THIS_FILE
, "stream_stop()"));
920 dev_idx
= strm
->param
.rec_id
;
922 if (tapi_dev_codec_control(dev_ctx
->ch_fd
[dev_idx
], 0) != PJ_SUCCESS
) {
923 TRACE_((THIS_FILE
, "ERROR - codec start failed!"));
931 stream_destroy(pjmedia_aud_stream
*s
)
933 pj_status_t state
= PJ_SUCCESS
;
934 struct tapi_aud_stream
*stream
= (struct tapi_aud_stream
*)s
;
937 PJ_ASSERT_RETURN(stream
!= NULL
, PJ_EINVAL
);
938 TRACE_((THIS_FILE
, "stream_destroy()"));
941 stream
->run_flag
= 0;
945 pj_thread_join(stream
->thread
);
946 pj_thread_destroy(stream
->thread
);
947 stream
->thread
= NULL
;
951 pj_bzero(stream
, sizeof(stream
));
952 pj_pool_release(pool
);
958 tapi_hook_status(pj_uint32_t port
, pj_uint32_t
*status
)
960 if (ioctl(ch_fd
[port
], IFX_TAPI_LINE_HOOK_STATUS_GET
, status
)
962 TRACE_((THIS_FILE
, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
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
);
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
));
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
));
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
);
990 ioctl(ch_fd
[port
], IFX_TAPI_RING_START
, 0);
993 ioctl(ch_fd
[port
], IFX_TAPI_RING_STOP
, 0);
1000 tapi_dial_tone(pj_uint32_t port
) {
1001 PJ_ASSERT_RETURN(port
< TAPI_AUDIO_PORT_NUM
, PJ_EINVAL
);
1003 ioctl(ch_fd
[port
], IFX_TAPI_TONE_DIALTONE_PLAY
, 0);
1009 tapi_no_tone(pj_uint32_t port
) {
1010 PJ_ASSERT_RETURN(port
< TAPI_AUDIO_PORT_NUM
, PJ_EINVAL
);
1012 ioctl(ch_fd
[port
], IFX_TAPI_TONE_LOCAL_PLAY
, 0);