1 From 455f6f2234a36aeeb97d3e05e9cbe3afad147341 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Sat, 28 Jan 2012 21:43:49 +0100
4 Subject: [PATCH 2/3] register tapi
7 .../pjmedia/src/pjmedia-audiodev/audiodev.c | 7 +
8 .../pjmedia/src/pjmedia-audiodev/tapi_dev.c | 1300 ++++++++++++++++++++
9 2 files changed, 1307 insertions(+), 0 deletions(-)
10 create mode 100644 pjproject-1.12/pjmedia/src/pjmedia-audiodev/tapi_dev.c
12 diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
13 index 3b7e121..82b364c 100644
14 --- a/pjmedia/src/pjmedia-audiodev/audiodev.c
15 +++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
16 @@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf);
17 pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
20 +#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
21 +pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf);
24 #define MAX_DRIVERS 16
27 @@ -409,6 +413,9 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf)
28 #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
29 aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
31 +#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
32 + aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_tapi_factory;
35 /* Initialize each factory and build the device ID list */
36 for (i=0; i<aud_subsys.drv_cnt; ++i) {
37 diff --git a/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
39 index 0000000..2c65a0d
41 +++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
43 +/******************************************************************************
46 + Lantiq Deutschland GmbH
47 + Am Campeon 3; 85579 Neubiberg, Germany
49 + For licensing information, see the file 'LICENSE' in the root folder of
50 + this software module.
52 +******************************************************************************/
53 +#include <pjmedia-audiodev/audiodev_imp.h>
54 +#include <pjmedia/errno.h>
55 +#include <pj/assert.h>
60 +#if defined(PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE) && PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
67 +#include <sys/stat.h>
69 +#include <sys/types.h>
70 +#include <sys/ioctl.h>
71 +#include <sys/select.h>
72 +#include <sys/time.h>
77 +#include "drv_tapi_io.h"
80 +/* Maximum 2 devices */
81 +#define TAPI_AUDIO_PORT_NUM 2
82 +#define TAPI_BASE_NAME "TAPI"
83 +#define TAPI_LL_DEV_BASE_PATH "/dev/vmmc"
84 +#define TAPI_LL_DEV_FIRMWARE_NAME "/lib/firmware/danube_firmware.bin"
85 +#define TAPI_LL_BBD_NAME "/lib/firmware/danube_bbd_fxs.bin"
87 +#define TAPI_LL_DEV_SELECT_TIMEOUT_MS 2000
88 +#define TAPI_LL_DEV_MAX_PACKET_SIZE 800
89 +#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE 12
90 +#define TAPI_LL_DEV_ENC_FRAME_LEN_MS 20
91 +#define TAPI_LL_DEV_ENC_SMPL_PER_SEC 8000
92 +#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS 16
93 +#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME 160
94 +#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
96 +#define THIS_FILE "tapi_dev.c"
98 +/* Set to 1 to enable tracing */
100 +# define TRACE_(expr) PJ_LOG(1,expr)
102 +# define TRACE_(expr)
105 +pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
110 + pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
111 + pj_int8_t data2phone_map[TAPI_AUDIO_PORT_NUM];
114 +struct tapi_aud_factory
116 + pjmedia_aud_dev_factory base;
118 + pj_pool_factory *pf;
119 + pj_uint32_t dev_count;
120 + pjmedia_aud_dev_info *dev_info;
124 +typedef struct tapi_aud_factory tapi_aud_factory_t;
126 +struct tapi_aud_stream
128 + pjmedia_aud_stream base;
130 + pjmedia_aud_param param;
131 + pjmedia_aud_rec_cb rec_cb;
132 + pjmedia_aud_play_cb play_cb;
135 + pj_thread_desc thread_desc;
136 + pj_thread_t *thread;
138 + pj_uint8_t run_flag;
139 + pj_timestamp timestamp;
142 +typedef struct tapi_aud_stream tapi_aud_stream_t;
144 +/* Factory prototypes */
145 +static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
146 +static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
147 +static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
148 +static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
150 + pjmedia_aud_dev_info *info);
151 +static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
153 + pjmedia_aud_param *param);
154 +static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
155 + const pjmedia_aud_param *param,
156 + pjmedia_aud_rec_cb rec_cb,
157 + pjmedia_aud_play_cb play_cb,
159 + pjmedia_aud_stream **p_aud_strm);
161 +/* Stream prototypes */
162 +static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
163 + pjmedia_aud_param *param);
164 +static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
165 + pjmedia_aud_dev_cap cap,
167 +static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
168 + pjmedia_aud_dev_cap cap,
169 + const void *value);
170 +static pj_status_t stream_start(pjmedia_aud_stream *strm);
171 +static pj_status_t stream_stop(pjmedia_aud_stream *strm);
172 +static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
174 +static pjmedia_aud_dev_factory_op tapi_fact_op =
178 + &factory_get_dev_count,
179 + &factory_get_dev_info,
180 + &factory_default_param,
181 + &factory_create_stream
184 +static pjmedia_aud_stream_op tapi_strm_op =
194 +/* TAPI configuration */
195 +static struct tapi_aud_stream streams[TAPI_AUDIO_PORT_NUM];
197 +void (*tapi_digit_callback)(pj_uint8_t port, pj_uint8_t digit) = NULL;
198 +void (*tapi_hook_callback)(pj_uint8_t port, pj_uint8_t event) = NULL;
200 +#define TAPI_TONE_LOCALE_NONE 32
201 +#define TAPI_TONE_LOCALE_BUSY_CODE 33
202 +#define TAPI_TONE_LOCALE_CONGESTION_CODE 34
203 +#define TAPI_TONE_LOCALE_DIAL_CODE 35
204 +#define TAPI_TONE_LOCALE_RING_CODE 36
205 +#define TAPI_TONE_LOCALE_WAITING_CODE 37
207 +static pj_uint8_t tapi_channel_revert = 0;
208 +static pj_uint8_t tapi_cid_type = 0;
209 +static pj_uint8_t tapi_locale = 0;
211 +void tapi_revert_channels(void)
213 + tapi_channel_revert = 1;
214 + PJ_LOG(3, (THIS_FILE, "using reverted configuration for TAPI channels"));
217 +void tapi_cid_select(char *cid)
219 + if (!stricmp(cid, "telecordia")) {
220 + tapi_cid_type = IFX_TAPI_CID_STD_TELCORDIA;
221 + PJ_LOG(3, (THIS_FILE, "using TELECORDIA configuration for TAPI CID"));
222 + } else if (!stricmp(cid, "etsi_fsk")) {
223 + tapi_cid_type = IFX_TAPI_CID_STD_ETSI_FSK;
224 + PJ_LOG(3, (THIS_FILE, "using ETSI FSK configuration for TAPI CID"));
225 + } else if (!stricmp(cid, "etsi_dtmf")) {
226 + tapi_cid_type = IFX_TAPI_CID_STD_ETSI_DTMF;
227 + PJ_LOG(3, (THIS_FILE, "using ETSI DTMF configuration for TAPI CID"));
228 + } else if (!stricmp(cid, "sin")) {
229 + tapi_cid_type = IFX_TAPI_CID_STD_SIN;
230 + PJ_LOG(3, (THIS_FILE, "using SIN CID configuration for TAPI CID"));
231 + } else if (!stricmp(cid, "ntt")) {
232 + tapi_cid_type = IFX_TAPI_CID_STD_NTT;
233 + PJ_LOG(3, (THIS_FILE, "using NTT configuration for TAPI CID"));
234 + } else if (!stricmp(cid, "kpn_dtmf")) {
235 + tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF;
236 + PJ_LOG(3, (THIS_FILE, "using KPN DTMF configuration for TAPI CID"));
237 + } else if (!stricmp(cid, "kpn_dtmf_fsk")) {
238 + tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF_FSK;
239 + PJ_LOG(3, (THIS_FILE, "using KPN DTMF FSK configuration for TAPI CID"));
243 +void tapi_locale_select(char *country)
245 + IFX_TAPI_TONE_t tone;
246 + pj_status_t status;
251 + if (!stricmp(country, "croatia")) {
252 + PJ_LOG(3, (THIS_FILE, "using localized tones for Croatia"));
254 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
255 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
256 + tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
257 + tone.simple.freqA = 425;
258 + tone.simple.levelA = 0;
259 + tone.simple.cadence[0] = 500;
260 + tone.simple.cadence[1] = 500;
261 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
262 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
263 + tone.simple.loop = 0;
264 + tone.simple.pause = 0;
265 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
266 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
267 + if (status != PJ_SUCCESS)
268 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
271 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
272 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
273 + tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
274 + tone.simple.freqA = 425;
275 + tone.simple.levelA = 0;
276 + tone.simple.cadence[0] = 250;
277 + tone.simple.cadence[1] = 250;
278 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
279 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
280 + tone.simple.loop = 0;
281 + tone.simple.pause = 0;
282 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
283 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
284 + if (status != PJ_SUCCESS)
285 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
288 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
289 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
290 + tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
291 + tone.simple.freqA = 425;
292 + tone.simple.levelA = 0;
293 + tone.simple.cadence[0] = 200;
294 + tone.simple.cadence[1] = 300;
295 + tone.simple.cadence[2] = 700;
296 + tone.simple.cadence[3] = 800;
297 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
298 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
299 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
300 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
301 + tone.simple.loop = 0;
302 + tone.simple.pause = 0;
303 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
304 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
305 + if (status != PJ_SUCCESS)
306 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
309 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
310 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
311 + tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
312 + tone.simple.freqA = 425;
313 + tone.simple.levelA = 0;
314 + tone.simple.cadence[0] = 1000;
315 + tone.simple.cadence[1] = 4000;
316 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
317 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
318 + tone.simple.loop = 0;
319 + tone.simple.pause = 0;
320 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
321 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
322 + if (status != PJ_SUCCESS)
323 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
326 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
327 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
328 + tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
329 + tone.simple.freqA = 425;
330 + tone.simple.levelA = 0;
331 + tone.simple.cadence[0] = 300;
332 + tone.simple.cadence[1] = 8000;
333 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
334 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
335 + tone.simple.loop = 0;
336 + tone.simple.pause = 0;
337 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
338 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
339 + if (status != PJ_SUCCESS)
340 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
342 + } else if (!stricmp(country, "germany")) {
343 + PJ_LOG(3, (THIS_FILE, "using localized tones for Germany"));
345 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
346 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
347 + tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
348 + tone.simple.freqA = 425;
349 + tone.simple.levelA = 0;
350 + tone.simple.cadence[0] = 480;
351 + tone.simple.cadence[1] = 480;
352 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
353 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
354 + tone.simple.loop = 0;
355 + tone.simple.pause = 0;
356 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
357 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
358 + if (status != PJ_SUCCESS)
359 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
362 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
363 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
364 + tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
365 + tone.simple.freqA = 425;
366 + tone.simple.levelA = 0;
367 + tone.simple.cadence[0] = 240;
368 + tone.simple.cadence[1] = 240;
369 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
370 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
371 + tone.simple.loop = 0;
372 + tone.simple.pause = 0;
373 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
374 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
375 + if (status != PJ_SUCCESS)
376 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
379 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
380 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
381 + tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
382 + tone.simple.freqA = 425;
383 + tone.simple.levelA = 0;
384 + tone.simple.cadence[0] = 1000;
385 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
386 + tone.simple.loop = 0;
387 + tone.simple.pause = 0;
388 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
389 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
390 + if (status != PJ_SUCCESS)
391 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
394 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
395 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
396 + tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
397 + tone.simple.freqA = 425;
398 + tone.simple.levelA = 0;
399 + tone.simple.cadence[0] = 1000;
400 + tone.simple.cadence[1] = 4000;
401 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
402 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
403 + tone.simple.loop = 0;
404 + tone.simple.pause = 0;
405 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
406 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
407 + if (status != PJ_SUCCESS)
408 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
411 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
412 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
413 + tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
414 + tone.simple.freqA = 425;
415 + tone.simple.levelA = 0;
416 + tone.simple.cadence[0] = 200;
417 + tone.simple.cadence[1] = 200;
418 + tone.simple.cadence[2] = 200;
419 + tone.simple.cadence[3] = 5000;
420 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
421 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
422 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
423 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
424 + tone.simple.loop = 0;
425 + tone.simple.pause = 0;
426 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
427 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
428 + if (status != PJ_SUCCESS)
429 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
435 +tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
437 + char devname[128] = { 0 };
438 + pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
439 + return open((const char*)devname, O_RDWR, 0644);
443 +tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
445 + pj_status_t status = PJ_SUCCESS;
447 + struct stat file_stat;
449 + fd = fopen(pPath, "rb");
451 + TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath));
452 + return PJ_EUNKNOWN;
455 + if (stat(pPath, &file_stat) != 0) {
456 + TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath));
457 + return PJ_EUNKNOWN;
460 + *ppBuf = malloc(file_stat.st_size);
461 + if (*ppBuf == NULL) {
462 + TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath));
463 + status = PJ_EUNKNOWN;
467 + if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
468 + TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
469 + status = PJ_EUNKNOWN;
473 + *pBufSz = file_stat.st_size;
479 + if (*ppBuf != NULL && status != PJ_SUCCESS)
486 +tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
493 +tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
495 + pj_status_t status = PJ_SUCCESS;
496 + pj_uint8_t *pFirmware = NULL;
497 + pj_uint32_t binSz = 0;
498 + VMMC_IO_INIT vmmc_io_init;
500 + status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
501 + if (status != PJ_SUCCESS) {
502 + TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
503 + return PJ_EUNKNOWN;
506 + memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
507 + vmmc_io_init.pPRAMfw = pFirmware;
508 + vmmc_io_init.pram_size = binSz;
510 + status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
511 + if (status != PJ_SUCCESS)
512 + TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!"));
514 + tapi_dev_binary_buffer_delete(pFirmware);
522 +tapi_dev_bbd_download(int fd, const char *pPath)
524 + int status = PJ_SUCCESS;
525 + unsigned char *pFirmware = NULL;
526 + unsigned int binSz = 0;
527 + VMMC_DWLD_t bbd_data;
530 + /* Create binary buffer */
531 + status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
532 + if (status != PJ_SUCCESS) {
533 + TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
537 + /* Download Voice Firmware */
538 + memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
539 + bbd_data.buf = pFirmware;
540 + bbd_data.size = binSz;
542 + status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
543 + if (status != PJ_SUCCESS) {
544 + TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
547 + /* Delete binary buffer */
548 + tapi_dev_binary_buffer_delete(pFirmware);
554 +static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
556 + pj_uint8_t c, hook_status;
557 + IFX_TAPI_TONE_t tone;
558 + IFX_TAPI_DEV_START_CFG_t tapistart;
559 + IFX_TAPI_MAP_DATA_t datamap;
560 + IFX_TAPI_ENC_CFG_t enc_cfg;
561 + IFX_TAPI_LINE_VOLUME_t line_vol;
562 + IFX_TAPI_WLEC_CFG_t lec_cfg;
563 + IFX_TAPI_JB_CFG_t jb_cfg;
564 + IFX_TAPI_CID_CFG_t cid_cfg;
565 + pj_status_t status;
568 + f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
570 + if (f->dev_ctx.dev_fd < 0) {
571 + TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
572 + return PJ_EUNKNOWN;
575 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
576 + if (tapi_channel_revert)
577 + ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, c + 1);
579 + ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
581 + if (f->dev_ctx.dev_fd < 0) {
582 + TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
583 + return PJ_EUNKNOWN;
585 + if (tapi_channel_revert)
586 + f->dev_ctx.data2phone_map[c] = c & 0x1 ? 1 : 0;
588 + f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
591 + status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
592 + if (status != PJ_SUCCESS) {
593 + TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
594 + return PJ_EUNKNOWN;
597 + /* Download coefficients */
599 + status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
600 + if (status != PJ_SUCCESS) {
601 + TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
602 + return PJ_EUNKNOWN;
606 + memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
607 + tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
610 + status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
611 + if (status != PJ_SUCCESS) {
612 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
613 + return PJ_EUNKNOWN;
617 + /* OpenWrt default tone */
618 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
619 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
620 + tone.simple.index = TAPI_TONE_LOCALE_NONE;
621 + tone.simple.freqA = 400;
622 + tone.simple.levelA = 0;
623 + tone.simple.freqB = 450;
624 + tone.simple.levelB = 0;
625 + tone.simple.freqC = 550;
626 + tone.simple.levelC = 0;
627 + tone.simple.freqD = 600;
628 + tone.simple.levelD = 0;
629 + tone.simple.cadence[0] = 100;
630 + tone.simple.cadence[1] = 150;
631 + tone.simple.cadence[2] = 100;
632 + tone.simple.cadence[3] = 150;
633 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA | IFX_TAPI_TONE_FREQB;
634 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
635 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQC | IFX_TAPI_TONE_FREQD;
636 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
637 + tone.simple.loop = 0;
638 + tone.simple.pause = 0;
639 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
640 + /* OpenWrt default tone */
641 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
642 + if (status != PJ_SUCCESS)
643 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
645 + /* Perform mapping */
646 + memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
647 + datamap.nDstCh = f->dev_ctx.data2phone_map[c];
648 + datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
650 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
651 + if (status != PJ_SUCCESS) {
652 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
653 + return PJ_EUNKNOWN;
656 + /* Set Line feed */
657 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
658 + if (status != PJ_SUCCESS) {
659 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
660 + return PJ_EUNKNOWN;
663 + /* Configure encoder for linear stream */
664 + memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
665 + enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
666 + enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8;
668 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
669 + if (status != PJ_SUCCESS) {
670 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
671 + return PJ_EUNKNOWN;
674 + /* Suppress TAPI volume, otherwise PJSIP starts autogeneration */
675 + memset(&line_vol, 0, sizeof(line_vol));
676 + line_vol.nGainRx = -8;
677 + line_vol.nGainTx = -8;
679 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
680 + if (status != PJ_SUCCESS) {
681 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
682 + return PJ_EUNKNOWN;
685 + /* Configure line echo canceller */
686 + memset(&lec_cfg, 0, sizeof(lec_cfg));
687 + lec_cfg.nType = IFX_TAPI_WLEC_TYPE_NFE;
688 + lec_cfg.bNlp = IFX_TAPI_LEC_NLP_OFF;
690 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_WLEC_PHONE_CFG_SET, &lec_cfg);
691 + if (status != PJ_SUCCESS) {
692 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_WLEC_PHONE_CFG_SET ioctl failed"));
693 + return PJ_EUNKNOWN;
696 + /* Configure jitter buffer */
697 + memset(&jb_cfg, 0, sizeof(jb_cfg));
698 + jb_cfg.nJbType = IFX_TAPI_JB_TYPE_ADAPTIVE;
699 + jb_cfg.nPckAdpt = IFX_TAPI_JB_PKT_ADAPT_VOICE;
700 + jb_cfg.nLocalAdpt = IFX_TAPI_JB_LOCAL_ADAPT_ON;
701 + jb_cfg.nScaling = 0x10;
702 + jb_cfg.nInitialSize = 0x2d0;
703 + jb_cfg.nMinSize = 0x50;
704 + jb_cfg.nMaxSize = 0x5a0;
706 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_JB_CFG_SET, &jb_cfg);
707 + if (status != PJ_SUCCESS) {
708 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_JB_CFG_SET ioctl failed"));
709 + return PJ_EUNKNOWN;
712 + /* Configure Caller ID type */
713 + if (tapi_cid_type) {
714 + memset(&cid_cfg, 0, sizeof(cid_cfg));
715 + cid_cfg.nStandard = tapi_cid_type;
716 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cfg);
717 + if (status != PJ_SUCCESS) {
718 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
719 + return PJ_EUNKNOWN;
723 + /* check hook status */
725 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
726 + if (status != PJ_SUCCESS) {
727 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
728 + return PJ_EUNKNOWN;
731 + /* if off hook do initialization */
733 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
734 + if (status != PJ_SUCCESS) {
735 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
736 + return PJ_EUNKNOWN;
738 + status = ioctl(c, IFX_TAPI_ENC_START, 0);
739 + if (status != PJ_SUCCESS) {
740 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
741 + return PJ_EUNKNOWN;
744 + status = ioctl(c, IFX_TAPI_DEC_START, 0);
745 + if (status != PJ_SUCCESS) {
746 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
747 + return PJ_EUNKNOWN;
756 +tapi_dev_stop(tapi_aud_factory_t *f)
758 + pj_status_t status = PJ_SUCCESS;
761 + if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
762 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
763 + status = PJ_EUNKNOWN;
766 + close(f->dev_ctx.dev_fd);
767 + for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
768 + close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
774 +tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
776 + if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
777 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
778 + start ? "START" : "STOP"));
779 + return PJ_EUNKNOWN;
782 + if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
783 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
784 + start ? "START" : "STOP"));
785 + return PJ_EUNKNOWN;
791 +static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
793 + PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
795 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
796 + IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
797 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
798 + return PJ_EUNKNOWN;
802 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
803 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
804 + return PJ_EUNKNOWN;
810 +static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
812 + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
814 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
815 + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
816 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
817 + return PJ_EUNKNOWN;
821 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
822 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
823 + return PJ_EUNKNOWN;
830 +tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
832 + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
834 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
835 + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
836 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
837 + return PJ_EUNKNOWN;
841 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
842 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
843 + return PJ_EUNKNOWN;
850 +tapi_dev_event_handler(tapi_aud_stream_t *stream)
852 + IFX_TAPI_EVENT_t tapiEvent;
853 + tapi_ctx *dev_ctx = stream->dev_ctx;
854 + pj_status_t status = PJ_SUCCESS;
857 + for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
858 + memset (&tapiEvent, 0, sizeof(tapiEvent));
859 + tapiEvent.ch = dev_ctx->data2phone_map[i];
860 + status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
862 + if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
863 + switch(tapiEvent.id) {
864 + case IFX_TAPI_EVENT_FXS_ONHOOK:
865 + status = tapi_dev_event_on_hook(dev_ctx, i);
866 + if(tapi_hook_callback)
867 + tapi_hook_callback(i, 0);
869 + case IFX_TAPI_EVENT_FXS_OFFHOOK:
870 + status = tapi_dev_event_off_hook(dev_ctx, i);
871 + if(tapi_hook_callback)
872 + tapi_hook_callback(i, 1);
874 + case IFX_TAPI_EVENT_DTMF_DIGIT:
875 + if(tapi_digit_callback)
876 + tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
878 + case IFX_TAPI_EVENT_COD_DEC_CHG:
879 + case IFX_TAPI_EVENT_TONE_GEN_END:
880 + case IFX_TAPI_EVENT_CID_TX_SEQ_END:
883 + PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
893 +tapi_dev_data_handler(tapi_aud_stream_t *stream) {
894 + pj_status_t status = PJ_SUCCESS;
895 + tapi_ctx *dev_ctx = stream->dev_ctx;
896 + pj_uint32_t dev_idx = stream->param.rec_id;
897 + pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
898 + pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
899 + pjmedia_frame frame_rec, frame_play;
902 + /* Get data from driver */
903 + ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
905 + TRACE_((THIS_FILE, "ERROR - no data available from device!"));
906 + return PJ_EUNKNOWN;
910 + frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
911 + frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
912 + frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
913 + frame_rec.timestamp.u64 = stream->timestamp.u64;
915 + status = stream->rec_cb(stream->user_data, &frame_rec);
916 + if (status != PJ_SUCCESS)
917 + PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
919 + frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
920 + frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
921 + frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
922 + frame_play.timestamp.u64 = stream->timestamp.u64;
924 + status = (*stream->play_cb)(stream->user_data, &frame_play);
925 + if (status != PJ_SUCCESS) {
926 + PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
928 + memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
930 + ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
933 + PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
934 + return PJ_EUNKNOWN;
938 + PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
939 + return PJ_EUNKNOWN;
943 + stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
950 +PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
951 + tapi_ctx *dev_ctx = streams[0].dev_ctx;
952 + pj_uint32_t sretval;
953 + struct pollfd fds[3];
955 + PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
957 + streams[0].run_flag = 1;
958 + streams[1].run_flag = 1;
960 + fds[0].fd = dev_ctx->dev_fd;
961 + fds[0].events = POLLIN;
962 + fds[1].fd = dev_ctx->ch_fd[0];
963 + fds[1].events = POLLIN;
964 + fds[2].fd = dev_ctx->ch_fd[1];
965 + fds[2].events = POLLIN;
969 + sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
971 + if (!streams[0].run_flag && !streams[0].run_flag)
976 + if (fds[0].revents == POLLIN) {
977 + if (tapi_dev_event_handler(&streams[0]) != PJ_SUCCESS) {
978 + PJ_LOG(1, (THIS_FILE, "TAPI: event hanldler failed"));
983 + if (fds[1].revents == POLLIN) {
984 + if (tapi_dev_data_handler(&streams[0]) != PJ_SUCCESS) {
985 + PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
990 + if (fds[2].revents == POLLIN) {
991 + if (tapi_dev_data_handler(&streams[1]) != PJ_SUCCESS) {
992 + PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
997 + PJ_LOG(1, (THIS_FILE, "TAPI: thread stopping..."));
1002 +/* Factory operations */
1004 +pjmedia_aud_dev_factory*
1005 +pjmedia_tapi_factory(pj_pool_factory *pf) {
1006 + struct tapi_aud_factory *f;
1009 + TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
1011 + pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
1012 + f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
1015 + f->base.op = &tapi_fact_op;
1021 +factory_init(pjmedia_aud_dev_factory *f)
1023 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1026 + TRACE_((THIS_FILE, "factory_init()"));
1028 + af->dev_count = TAPI_AUDIO_PORT_NUM;
1029 + af->dev_info = (pjmedia_aud_dev_info*)
1030 + pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
1031 + for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
1032 + pj_ansi_sprintf(af->dev_info[i].name,"%s_%02d", TAPI_BASE_NAME, i);
1033 + af->dev_info[i].input_count = af->dev_info[i].output_count = 1;
1034 + af->dev_info[i].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
1035 + pj_ansi_strcpy(af->dev_info[i].driver, "/dev/vmmc");
1036 + af->dev_info[i].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
1037 + PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
1038 + PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1039 + af->dev_info[i].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
1041 + if (tapi_dev_start(af) != PJ_SUCCESS) {
1042 + TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
1043 + return PJ_EUNKNOWN;
1046 + return PJ_SUCCESS;
1050 +factory_destroy(pjmedia_aud_dev_factory *f)
1052 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1054 + pj_status_t status = PJ_SUCCESS;
1056 + TRACE_((THIS_FILE, "factory_destroy()"));
1058 + if (tapi_dev_stop(af) != PJ_SUCCESS) {
1059 + TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
1060 + status = PJ_EUNKNOWN;
1064 + pj_pool_release(pool);
1070 +factory_get_dev_count(pjmedia_aud_dev_factory *f)
1072 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1073 + TRACE_((THIS_FILE, "factory_get_dev_count()"));
1075 + return af->dev_count;
1079 +factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
1081 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1083 + TRACE_((THIS_FILE, "factory_get_dev_info()"));
1084 + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1086 + pj_memcpy(info, &af->dev_info[index], sizeof(*info));
1088 + return PJ_SUCCESS;
1092 +factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
1094 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1095 + struct pjmedia_aud_dev_info *di = &af->dev_info[index];
1097 + TRACE_((THIS_FILE, "factory_default_param."));
1098 + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1100 + pj_bzero(param, sizeof(*param));
1101 + if (di->input_count && di->output_count) {
1102 + param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
1103 + param->rec_id = index;
1104 + param->play_id = index;
1105 + } else if (di->input_count) {
1106 + param->dir = PJMEDIA_DIR_CAPTURE;
1107 + param->rec_id = index;
1108 + param->play_id = PJMEDIA_AUD_INVALID_DEV;
1109 + } else if (di->output_count) {
1110 + param->dir = PJMEDIA_DIR_PLAYBACK;
1111 + param->play_id = index;
1112 + param->rec_id = PJMEDIA_AUD_INVALID_DEV;
1114 + return PJMEDIA_EAUD_INVDEV;
1117 + param->clock_rate = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
1118 + param->channel_count = 1;
1119 + param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
1120 + param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
1121 + param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
1122 + param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
1124 + return PJ_SUCCESS;
1129 +factory_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param,
1130 + pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb,
1131 + void *user_data, pjmedia_aud_stream **p_aud_strm)
1133 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1135 + pj_status_t status;
1136 + int id = param->rec_id;
1137 + struct tapi_aud_stream *strm = &streams[param->rec_id];
1138 + TRACE_((THIS_FILE, "factory_create_stream() rec_id:%d play_id:%d", param->rec_id, param->play_id));
1140 + /* Can only support 16bits per sample */
1141 + PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
1142 + PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
1143 + PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
1145 + /* Can only support bidirectional stream */
1146 + PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
1149 + /* Initialize our stream data */
1150 + pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
1151 + PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
1153 + strm->pool = pool;
1155 + pool = strm->pool = streams[0].pool;
1158 + strm->rec_cb = rec_cb;
1159 + strm->play_cb = play_cb;
1160 + strm->user_data = user_data;
1162 + pj_memcpy(&strm->param, param, sizeof(*param));
1164 + if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
1165 + strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
1168 + strm->timestamp.u64 = 0;
1169 + strm->dev_ctx = &(af->dev_ctx);
1171 + /* Create and start the thread */
1173 + status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, &streams[0].thread);
1174 + if (status != PJ_SUCCESS) {
1175 + stream_destroy(&strm->base);
1181 + strm->base.op = &tapi_strm_op;
1182 + *p_aud_strm = &strm->base;
1184 + return PJ_SUCCESS;
1188 +stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
1190 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1192 + PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1193 + pj_memcpy(pi, &strm->param, sizeof(*pi));
1195 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1196 + &pi->output_vol) == PJ_SUCCESS)
1197 + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1199 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
1200 + &pi->output_latency_ms) == PJ_SUCCESS)
1201 + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
1203 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
1204 + &pi->input_latency_ms) == PJ_SUCCESS)
1205 + pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1207 + return PJ_SUCCESS;
1211 +stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
1213 + // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1214 + return PJ_SUCCESS;
1218 +stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
1220 + // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1221 + return PJ_SUCCESS;
1225 +stream_start(pjmedia_aud_stream *s)
1227 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1228 + pj_uint32_t dev_idx;
1230 + TRACE_((THIS_FILE, "stream_start()"));
1232 + dev_idx = strm->param.rec_id;
1234 + return PJ_SUCCESS;
1238 +stream_stop(pjmedia_aud_stream *s)
1240 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1241 + tapi_ctx *dev_ctx = strm->dev_ctx;
1242 + pj_uint32_t dev_idx;
1244 + TRACE_((THIS_FILE, "stream_stop()"));
1245 + dev_idx = strm->param.rec_id;
1247 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
1248 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
1249 + return PJ_EUNKNOWN;
1252 + return PJ_SUCCESS;
1256 +stream_destroy(pjmedia_aud_stream *s)
1258 + pj_status_t state = PJ_SUCCESS;
1259 + struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
1262 + PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
1263 + TRACE_((THIS_FILE, "stream_destroy()"));
1265 + stream_stop(&stream->base);
1266 + stream->run_flag = 0;
1268 + if (stream->thread)
1270 + pj_thread_join(stream->thread);
1271 + pj_thread_destroy(stream->thread);
1272 + stream->thread = NULL;
1275 + pool = stream->pool;
1276 + pj_bzero(stream, sizeof(stream));
1277 + pj_pool_release(pool);
1283 +tapi_hook_status(pj_uint8_t port, pj_int32_t *status)
1285 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1287 + if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
1289 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
1290 + return PJ_EUNKNOWN;
1293 + return PJ_SUCCESS;
1297 +tapi_ring(pj_uint8_t port, pj_uint8_t state, char *caller_number)
1299 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1302 + if (tapi_cid_type && caller_number) {
1303 + IFX_TAPI_CID_MSG_t cid_msg;
1304 + IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
1305 + memset(&cid_msg, 0, sizeof(cid_msg));
1306 + memset(&cid_msg_el, 0, sizeof(cid_msg_el));
1308 + cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
1309 + cid_msg_el[0].string.len = strlen(caller_number);
1310 + strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
1312 + cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
1313 + cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
1314 + cid_msg.nMsgElements = 1;
1315 + cid_msg.message = cid_msg_el;
1316 + ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
1318 + ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
1321 + ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
1324 + return PJ_SUCCESS;
1328 +tapi_tone(pj_uint8_t port, pj_uint8_t code)
1330 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1332 + if (tapi_locale && code)
1333 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, code);
1335 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, TAPI_TONE_LOCALE_NONE);
1337 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
1339 + return PJ_SUCCESS;
1342 +#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */