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);