1 --- a/pjmedia/src/pjmedia-audiodev/audiodev.c
2 +++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
3 @@ -98,6 +98,10 @@ pjmedia_aud_dev_factory* pjmedia_symb_md
4 pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf);
7 +#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
8 +pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf);
11 #define MAX_DRIVERS 16
14 @@ -409,6 +413,9 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_i
15 #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
16 aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
18 +#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
19 + aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_tapi_factory;
22 /* Initialize each factory and build the device ID list */
23 for (i=0; i<aud_subsys.drv_cnt; ++i) {
25 +++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c
27 +/******************************************************************************
30 + Lantiq Deutschland GmbH
31 + Am Campeon 3; 85579 Neubiberg, Germany
33 + For licensing information, see the file 'LICENSE' in the root folder of
34 + this software module.
36 +******************************************************************************/
37 +#include <pjmedia-audiodev/audiodev_imp.h>
38 +#include <pjmedia/errno.h>
39 +#include <pj/assert.h>
44 +#if defined(PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE) && PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE
51 +#include <sys/stat.h>
53 +#include <sys/types.h>
54 +#include <sys/ioctl.h>
55 +#include <sys/select.h>
56 +#include <sys/time.h>
61 +#include "drv_tapi_io.h"
64 +/* Maximum 2 devices */
65 +#define TAPI_AUDIO_PORT_NUM 2
66 +#define TAPI_BASE_NAME "TAPI"
67 +#define TAPI_LL_DEV_BASE_PATH "/dev/vmmc"
68 +#define TAPI_LL_DEV_FIRMWARE_NAME "/lib/firmware/danube_firmware.bin"
69 +#define TAPI_LL_BBD_NAME "/lib/firmware/danube_bbd_fxs.bin"
71 +#define TAPI_LL_DEV_SELECT_TIMEOUT_MS 2000
72 +#define TAPI_LL_DEV_MAX_PACKET_SIZE 800
73 +#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE 12
74 +#define TAPI_LL_DEV_ENC_FRAME_LEN_MS 20
75 +#define TAPI_LL_DEV_ENC_SMPL_PER_SEC 8000
76 +#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS 16
77 +#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME 160
78 +#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8))
80 +#define THIS_FILE "tapi_dev.c"
82 +/* Set to 1 to enable tracing */
84 +# define TRACE_(expr) PJ_LOG(1,expr)
86 +# define TRACE_(expr)
89 +pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
94 + pj_int32_t ch_fd[TAPI_AUDIO_PORT_NUM];
95 + pj_int8_t data2phone_map[TAPI_AUDIO_PORT_NUM];
98 +struct tapi_aud_factory
100 + pjmedia_aud_dev_factory base;
102 + pj_pool_factory *pf;
103 + pj_uint32_t dev_count;
104 + pjmedia_aud_dev_info *dev_info;
108 +typedef struct tapi_aud_factory tapi_aud_factory_t;
110 +struct tapi_aud_stream
112 + pjmedia_aud_stream base;
114 + pjmedia_aud_param param;
115 + pjmedia_aud_rec_cb rec_cb;
116 + pjmedia_aud_play_cb play_cb;
119 + pj_thread_desc thread_desc;
120 + pj_thread_t *thread;
122 + pj_uint8_t run_flag;
123 + pj_timestamp timestamp;
126 +typedef struct tapi_aud_stream tapi_aud_stream_t;
128 +/* Factory prototypes */
129 +static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
130 +static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
131 +static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
132 +static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
134 + pjmedia_aud_dev_info *info);
135 +static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
137 + pjmedia_aud_param *param);
138 +static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
139 + const pjmedia_aud_param *param,
140 + pjmedia_aud_rec_cb rec_cb,
141 + pjmedia_aud_play_cb play_cb,
143 + pjmedia_aud_stream **p_aud_strm);
145 +/* Stream prototypes */
146 +static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
147 + pjmedia_aud_param *param);
148 +static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
149 + pjmedia_aud_dev_cap cap,
151 +static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
152 + pjmedia_aud_dev_cap cap,
153 + const void *value);
154 +static pj_status_t stream_start(pjmedia_aud_stream *strm);
155 +static pj_status_t stream_stop(pjmedia_aud_stream *strm);
156 +static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
158 +static pjmedia_aud_dev_factory_op tapi_fact_op =
162 + &factory_get_dev_count,
163 + &factory_get_dev_info,
164 + &factory_default_param,
165 + &factory_create_stream
168 +static pjmedia_aud_stream_op tapi_strm_op =
178 +/* TAPI configuration */
179 +static struct tapi_aud_stream streams[TAPI_AUDIO_PORT_NUM];
181 +void (*tapi_digit_callback)(pj_uint8_t port, pj_uint8_t digit) = NULL;
182 +void (*tapi_hook_callback)(pj_uint8_t port, pj_uint8_t event) = NULL;
184 +#define TAPI_TONE_LOCALE_NONE 32
185 +#define TAPI_TONE_LOCALE_BUSY_CODE 33
186 +#define TAPI_TONE_LOCALE_CONGESTION_CODE 34
187 +#define TAPI_TONE_LOCALE_DIAL_CODE 35
188 +#define TAPI_TONE_LOCALE_RING_CODE 36
189 +#define TAPI_TONE_LOCALE_WAITING_CODE 37
191 +static pj_uint8_t tapi_channel_revert = 0;
192 +static pj_uint8_t tapi_cid_type = 0;
193 +static pj_uint8_t tapi_locale = 0;
195 +void tapi_revert_channels(void)
197 + tapi_channel_revert = 1;
198 + PJ_LOG(3, (THIS_FILE, "using reverted configuration for TAPI channels"));
201 +void tapi_cid_select(char *cid)
203 + if (!stricmp(cid, "telecordia")) {
204 + tapi_cid_type = IFX_TAPI_CID_STD_TELCORDIA;
205 + PJ_LOG(3, (THIS_FILE, "using TELECORDIA configuration for TAPI CID"));
206 + } else if (!stricmp(cid, "etsi_fsk")) {
207 + tapi_cid_type = IFX_TAPI_CID_STD_ETSI_FSK;
208 + PJ_LOG(3, (THIS_FILE, "using ETSI FSK configuration for TAPI CID"));
209 + } else if (!stricmp(cid, "etsi_dtmf")) {
210 + tapi_cid_type = IFX_TAPI_CID_STD_ETSI_DTMF;
211 + PJ_LOG(3, (THIS_FILE, "using ETSI DTMF configuration for TAPI CID"));
212 + } else if (!stricmp(cid, "sin")) {
213 + tapi_cid_type = IFX_TAPI_CID_STD_SIN;
214 + PJ_LOG(3, (THIS_FILE, "using SIN CID configuration for TAPI CID"));
215 + } else if (!stricmp(cid, "ntt")) {
216 + tapi_cid_type = IFX_TAPI_CID_STD_NTT;
217 + PJ_LOG(3, (THIS_FILE, "using NTT configuration for TAPI CID"));
218 + } else if (!stricmp(cid, "kpn_dtmf")) {
219 + tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF;
220 + PJ_LOG(3, (THIS_FILE, "using KPN DTMF configuration for TAPI CID"));
221 + } else if (!stricmp(cid, "kpn_dtmf_fsk")) {
222 + tapi_cid_type = IFX_TAPI_CID_STD_KPN_DTMF_FSK;
223 + PJ_LOG(3, (THIS_FILE, "using KPN DTMF FSK configuration for TAPI CID"));
227 +void tapi_locale_select(char *country)
229 + IFX_TAPI_TONE_t tone;
230 + pj_status_t status;
235 + if (!stricmp(country, "croatia")) {
236 + PJ_LOG(3, (THIS_FILE, "using localized tones for Croatia"));
238 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
239 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
240 + tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
241 + tone.simple.freqA = 425;
242 + tone.simple.levelA = 0;
243 + tone.simple.cadence[0] = 500;
244 + tone.simple.cadence[1] = 500;
245 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
246 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
247 + tone.simple.loop = 0;
248 + tone.simple.pause = 0;
249 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
250 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
251 + if (status != PJ_SUCCESS)
252 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
255 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
256 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
257 + tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
258 + tone.simple.freqA = 425;
259 + tone.simple.levelA = 0;
260 + tone.simple.cadence[0] = 250;
261 + tone.simple.cadence[1] = 250;
262 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
263 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
264 + tone.simple.loop = 0;
265 + tone.simple.pause = 0;
266 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
267 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
268 + if (status != PJ_SUCCESS)
269 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
272 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
273 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
274 + tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
275 + tone.simple.freqA = 425;
276 + tone.simple.levelA = 0;
277 + tone.simple.cadence[0] = 200;
278 + tone.simple.cadence[1] = 300;
279 + tone.simple.cadence[2] = 700;
280 + tone.simple.cadence[3] = 800;
281 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
282 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
283 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
284 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
285 + tone.simple.loop = 0;
286 + tone.simple.pause = 0;
287 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
288 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
289 + if (status != PJ_SUCCESS)
290 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
293 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
294 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
295 + tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
296 + tone.simple.freqA = 425;
297 + tone.simple.levelA = 0;
298 + tone.simple.cadence[0] = 1000;
299 + tone.simple.cadence[1] = 4000;
300 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
301 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
302 + tone.simple.loop = 0;
303 + tone.simple.pause = 0;
304 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
305 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
306 + if (status != PJ_SUCCESS)
307 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
310 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
311 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
312 + tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
313 + tone.simple.freqA = 425;
314 + tone.simple.levelA = 0;
315 + tone.simple.cadence[0] = 300;
316 + tone.simple.cadence[1] = 8000;
317 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
318 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
319 + tone.simple.loop = 0;
320 + tone.simple.pause = 0;
321 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
322 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
323 + if (status != PJ_SUCCESS)
324 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
326 + } else if (!stricmp(country, "germany")) {
327 + PJ_LOG(3, (THIS_FILE, "using localized tones for Germany"));
329 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
330 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
331 + tone.simple.index = TAPI_TONE_LOCALE_BUSY_CODE;
332 + tone.simple.freqA = 425;
333 + tone.simple.levelA = 0;
334 + tone.simple.cadence[0] = 480;
335 + tone.simple.cadence[1] = 480;
336 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
337 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
338 + tone.simple.loop = 0;
339 + tone.simple.pause = 0;
340 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
341 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
342 + if (status != PJ_SUCCESS)
343 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
346 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
347 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
348 + tone.simple.index = TAPI_TONE_LOCALE_CONGESTION_CODE;
349 + tone.simple.freqA = 425;
350 + tone.simple.levelA = 0;
351 + tone.simple.cadence[0] = 240;
352 + tone.simple.cadence[1] = 240;
353 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
354 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
355 + tone.simple.loop = 0;
356 + tone.simple.pause = 0;
357 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
358 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
359 + if (status != PJ_SUCCESS)
360 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
363 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
364 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
365 + tone.simple.index = TAPI_TONE_LOCALE_DIAL_CODE;
366 + tone.simple.freqA = 425;
367 + tone.simple.levelA = 0;
368 + tone.simple.cadence[0] = 1000;
369 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
370 + tone.simple.loop = 0;
371 + tone.simple.pause = 0;
372 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
373 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
374 + if (status != PJ_SUCCESS)
375 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
378 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
379 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
380 + tone.simple.index = TAPI_TONE_LOCALE_RING_CODE;
381 + tone.simple.freqA = 425;
382 + tone.simple.levelA = 0;
383 + tone.simple.cadence[0] = 1000;
384 + tone.simple.cadence[1] = 4000;
385 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
386 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
387 + tone.simple.loop = 0;
388 + tone.simple.pause = 0;
389 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
390 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
391 + if (status != PJ_SUCCESS)
392 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
395 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
396 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
397 + tone.simple.index = TAPI_TONE_LOCALE_WAITING_CODE;
398 + tone.simple.freqA = 425;
399 + tone.simple.levelA = 0;
400 + tone.simple.cadence[0] = 200;
401 + tone.simple.cadence[1] = 200;
402 + tone.simple.cadence[2] = 200;
403 + tone.simple.cadence[3] = 5000;
404 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA;
405 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
406 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQA;
407 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
408 + tone.simple.loop = 0;
409 + tone.simple.pause = 0;
410 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
411 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
412 + if (status != PJ_SUCCESS)
413 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
419 +tapi_dev_open(char* dev_path, const pj_int32_t ch_num)
421 + char devname[128] = { 0 };
422 + pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num);
423 + return open((const char*)devname, O_RDWR, 0644);
427 +tapi_dev_binary_buffer_create(const char *pPath, pj_uint8_t **ppBuf, pj_uint32_t *pBufSz)
429 + pj_status_t status = PJ_SUCCESS;
431 + struct stat file_stat;
433 + fd = fopen(pPath, "rb");
435 + TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath));
436 + return PJ_EUNKNOWN;
439 + if (stat(pPath, &file_stat) != 0) {
440 + TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath));
441 + return PJ_EUNKNOWN;
444 + *ppBuf = malloc(file_stat.st_size);
445 + if (*ppBuf == NULL) {
446 + TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath));
447 + status = PJ_EUNKNOWN;
451 + if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) {
452 + TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath));
453 + status = PJ_EUNKNOWN;
457 + *pBufSz = file_stat.st_size;
463 + if (*ppBuf != NULL && status != PJ_SUCCESS)
470 +tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf)
477 +tapi_dev_firmware_download(pj_int32_t fd, const char *pPath)
479 + pj_status_t status = PJ_SUCCESS;
480 + pj_uint8_t *pFirmware = NULL;
481 + pj_uint32_t binSz = 0;
482 + VMMC_IO_INIT vmmc_io_init;
484 + status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
485 + if (status != PJ_SUCCESS) {
486 + TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
487 + return PJ_EUNKNOWN;
490 + memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT));
491 + vmmc_io_init.pPRAMfw = pFirmware;
492 + vmmc_io_init.pram_size = binSz;
494 + status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init);
495 + if (status != PJ_SUCCESS)
496 + TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!"));
498 + tapi_dev_binary_buffer_delete(pFirmware);
506 +tapi_dev_bbd_download(int fd, const char *pPath)
508 + int status = PJ_SUCCESS;
509 + unsigned char *pFirmware = NULL;
510 + unsigned int binSz = 0;
511 + VMMC_DWLD_t bbd_data;
514 + /* Create binary buffer */
515 + status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz);
516 + if (status != PJ_SUCCESS) {
517 + TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n"));
521 + /* Download Voice Firmware */
522 + memset(&bbd_data, 0, sizeof(VMMC_DWLD_t));
523 + bbd_data.buf = pFirmware;
524 + bbd_data.size = binSz;
526 + status = ioctl(fd, FIO_BBD_DOWNLOAD, &bbd_data);
527 + if (status != PJ_SUCCESS) {
528 + TRACE_((THIS_FILE, "ERROR - FIO_BBD_DOWNLOAD failed!\n"));
531 + /* Delete binary buffer */
532 + tapi_dev_binary_buffer_delete(pFirmware);
538 +static pj_status_t tapi_dev_start(tapi_aud_factory_t *f)
540 + pj_uint8_t c, hook_status;
541 + IFX_TAPI_TONE_t tone;
542 + IFX_TAPI_DEV_START_CFG_t tapistart;
543 + IFX_TAPI_MAP_DATA_t datamap;
544 + IFX_TAPI_ENC_CFG_t enc_cfg;
545 + IFX_TAPI_LINE_VOLUME_t line_vol;
546 + IFX_TAPI_WLEC_CFG_t lec_cfg;
547 + IFX_TAPI_JB_CFG_t jb_cfg;
548 + IFX_TAPI_CID_CFG_t cid_cfg;
549 + pj_status_t status;
552 + f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0);
554 + if (f->dev_ctx.dev_fd < 0) {
555 + TRACE_((THIS_FILE, "ERROR - TAPI device open failed!"));
556 + return PJ_EUNKNOWN;
559 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
560 + if (tapi_channel_revert)
561 + ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, c + 1);
563 + ch_fd[c] = f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_PORT_NUM - c);
565 + if (f->dev_ctx.dev_fd < 0) {
566 + TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c));
567 + return PJ_EUNKNOWN;
569 + if (tapi_channel_revert)
570 + f->dev_ctx.data2phone_map[c] = c & 0x1 ? 1 : 0;
572 + f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1;
575 + status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME);
576 + if (status != PJ_SUCCESS) {
577 + TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!"));
578 + return PJ_EUNKNOWN;
581 + /* Download coefficients */
583 + status = tapi_dev_bbd_download(f->dev_ctx.dev_fd, TAPI_LL_BBD_NAME);
584 + if (status != PJ_SUCCESS) {
585 + TRACE_((THIS_FILE, "ERROR - Voice Coefficients Download failed!"));
586 + return PJ_EUNKNOWN;
590 + memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t));
591 + tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER;
594 + status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart);
595 + if (status != PJ_SUCCESS) {
596 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed"));
597 + return PJ_EUNKNOWN;
601 + /* OpenWrt default tone */
602 + memset(&tone, 0, sizeof(IFX_TAPI_TONE_t));
603 + tone.simple.format = IFX_TAPI_TONE_TYPE_SIMPLE;
604 + tone.simple.index = TAPI_TONE_LOCALE_NONE;
605 + tone.simple.freqA = 400;
606 + tone.simple.levelA = 0;
607 + tone.simple.freqB = 450;
608 + tone.simple.levelB = 0;
609 + tone.simple.freqC = 550;
610 + tone.simple.levelC = 0;
611 + tone.simple.freqD = 600;
612 + tone.simple.levelD = 0;
613 + tone.simple.cadence[0] = 100;
614 + tone.simple.cadence[1] = 150;
615 + tone.simple.cadence[2] = 100;
616 + tone.simple.cadence[3] = 150;
617 + tone.simple.frequencies[0] = IFX_TAPI_TONE_FREQA | IFX_TAPI_TONE_FREQB;
618 + tone.simple.frequencies[1] = IFX_TAPI_TONE_FREQNONE;
619 + tone.simple.frequencies[2] = IFX_TAPI_TONE_FREQC | IFX_TAPI_TONE_FREQD;
620 + tone.simple.frequencies[3] = IFX_TAPI_TONE_FREQNONE;
621 + tone.simple.loop = 0;
622 + tone.simple.pause = 0;
623 + for (c = 0; c < TAPI_AUDIO_PORT_NUM; c++) {
624 + /* OpenWrt default tone */
625 + status = ioctl(ch_fd[c], IFX_TAPI_TONE_TABLE_CFG_SET, &tone);
626 + if (status != PJ_SUCCESS)
627 + TRACE_((THIS_FILE, "IFX_TAPI_TONE_TABLE_CFG_SET failed!\n"));
629 + /* Perform mapping */
630 + memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t));
631 + datamap.nDstCh = f->dev_ctx.data2phone_map[c];
632 + datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE;
634 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap);
635 + if (status != PJ_SUCCESS) {
636 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed"));
637 + return PJ_EUNKNOWN;
640 + /* Set Line feed */
641 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY);
642 + if (status != PJ_SUCCESS) {
643 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed"));
644 + return PJ_EUNKNOWN;
647 + /* Configure encoder for linear stream */
648 + memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t));
649 + enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20;
650 + enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8;
652 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg);
653 + if (status != PJ_SUCCESS) {
654 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed"));
655 + return PJ_EUNKNOWN;
658 + /* Suppress TAPI volume, otherwise PJSIP starts autogeneration */
659 + memset(&line_vol, 0, sizeof(line_vol));
660 + line_vol.nGainRx = -8;
661 + line_vol.nGainTx = -8;
663 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &line_vol);
664 + if (status != PJ_SUCCESS) {
665 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed"));
666 + return PJ_EUNKNOWN;
669 + /* Configure line echo canceller */
670 + memset(&lec_cfg, 0, sizeof(lec_cfg));
671 + lec_cfg.nType = IFX_TAPI_WLEC_TYPE_NFE;
672 + lec_cfg.bNlp = IFX_TAPI_LEC_NLP_OFF;
674 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_WLEC_PHONE_CFG_SET, &lec_cfg);
675 + if (status != PJ_SUCCESS) {
676 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_WLEC_PHONE_CFG_SET ioctl failed"));
677 + return PJ_EUNKNOWN;
680 + /* Configure jitter buffer */
681 + memset(&jb_cfg, 0, sizeof(jb_cfg));
682 + jb_cfg.nJbType = IFX_TAPI_JB_TYPE_ADAPTIVE;
683 + jb_cfg.nPckAdpt = IFX_TAPI_JB_PKT_ADAPT_VOICE;
684 + jb_cfg.nLocalAdpt = IFX_TAPI_JB_LOCAL_ADAPT_ON;
685 + jb_cfg.nScaling = 0x10;
686 + jb_cfg.nInitialSize = 0x2d0;
687 + jb_cfg.nMinSize = 0x50;
688 + jb_cfg.nMaxSize = 0x5a0;
690 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_JB_CFG_SET, &jb_cfg);
691 + if (status != PJ_SUCCESS) {
692 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_JB_CFG_SET ioctl failed"));
693 + return PJ_EUNKNOWN;
696 + /* Configure Caller ID type */
697 + if (tapi_cid_type) {
698 + memset(&cid_cfg, 0, sizeof(cid_cfg));
699 + cid_cfg.nStandard = tapi_cid_type;
700 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_CID_CFG_SET, &cid_cfg);
701 + if (status != PJ_SUCCESS) {
702 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_CID_CFG_SET ioctl failed"));
703 + return PJ_EUNKNOWN;
707 + /* check hook status */
709 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_HOOK_STATUS_GET, &hook_status);
710 + if (status != PJ_SUCCESS) {
711 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
712 + return PJ_EUNKNOWN;
715 + /* if off hook do initialization */
717 + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_ACTIVE);
718 + if (status != PJ_SUCCESS) {
719 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
720 + return PJ_EUNKNOWN;
722 + status = ioctl(c, IFX_TAPI_ENC_START, 0);
723 + if (status != PJ_SUCCESS) {
724 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_START ioctl failed!"));
725 + return PJ_EUNKNOWN;
728 + status = ioctl(c, IFX_TAPI_DEC_START, 0);
729 + if (status != PJ_SUCCESS) {
730 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_START ioctl failed!"));
731 + return PJ_EUNKNOWN;
740 +tapi_dev_stop(tapi_aud_factory_t *f)
742 + pj_status_t status = PJ_SUCCESS;
745 + if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) {
746 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed"));
747 + status = PJ_EUNKNOWN;
750 + close(f->dev_ctx.dev_fd);
751 + for (c = TAPI_AUDIO_PORT_NUM; c > 0; c--)
752 + close(f->dev_ctx.ch_fd[TAPI_AUDIO_PORT_NUM-c]);
758 +tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start)
760 + if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) {
761 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!",
762 + start ? "START" : "STOP"));
763 + return PJ_EUNKNOWN;
766 + if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) {
767 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!",
768 + start ? "START" : "STOP"));
769 + return PJ_EUNKNOWN;
775 +static pj_status_t tapi_dev_event_on_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
777 + PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK"));
779 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
780 + IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) {
781 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
782 + return PJ_EUNKNOWN;
786 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
787 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
788 + return PJ_EUNKNOWN;
794 +static pj_status_t tapi_dev_event_off_hook(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
796 + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
798 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
799 + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
800 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
801 + return PJ_EUNKNOWN;
805 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
806 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
807 + return PJ_EUNKNOWN;
814 +tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx)
816 + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK"));
818 + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET,
819 + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) {
820 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!"));
821 + return PJ_EUNKNOWN;
825 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) {
826 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
827 + return PJ_EUNKNOWN;
834 +tapi_dev_event_handler(tapi_aud_stream_t *stream)
836 + IFX_TAPI_EVENT_t tapiEvent;
837 + tapi_ctx *dev_ctx = stream->dev_ctx;
838 + pj_status_t status = PJ_SUCCESS;
841 + for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
842 + memset (&tapiEvent, 0, sizeof(tapiEvent));
843 + tapiEvent.ch = dev_ctx->data2phone_map[i];
844 + status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent);
846 + if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) {
847 + switch(tapiEvent.id) {
848 + case IFX_TAPI_EVENT_FXS_ONHOOK:
849 + status = tapi_dev_event_on_hook(dev_ctx, i);
850 + if(tapi_hook_callback)
851 + tapi_hook_callback(i, 0);
853 + case IFX_TAPI_EVENT_FXS_OFFHOOK:
854 + status = tapi_dev_event_off_hook(dev_ctx, i);
855 + if(tapi_hook_callback)
856 + tapi_hook_callback(i, 1);
858 + case IFX_TAPI_EVENT_DTMF_DIGIT:
859 + if(tapi_digit_callback)
860 + tapi_digit_callback(i, tapiEvent.data.dtmf.ascii);
862 + case IFX_TAPI_EVENT_PULSE_DIGIT:
863 + if(tapi_digit_callback)
864 + if(tapiEvent.data.pulse.digit == 0xB)
865 + tapi_digit_callback(i, '0');
867 + tapi_digit_callback(i, '0' + tapiEvent.data.pulse.digit);
869 + case IFX_TAPI_EVENT_COD_DEC_CHG:
870 + case IFX_TAPI_EVENT_TONE_GEN_END:
871 + case IFX_TAPI_EVENT_CID_TX_SEQ_END:
874 + PJ_LOG(1,(THIS_FILE, "unknown tapi event %08X", tapiEvent.id));
884 +tapi_dev_data_handler(tapi_aud_stream_t *stream) {
885 + pj_status_t status = PJ_SUCCESS;
886 + tapi_ctx *dev_ctx = stream->dev_ctx;
887 + pj_uint32_t dev_idx = stream->param.rec_id;
888 + pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
889 + pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0};
890 + pjmedia_frame frame_rec, frame_play;
893 + /* Get data from driver */
894 + ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec));
896 + TRACE_((THIS_FILE, "ERROR - no data available from device!"));
897 + return PJ_EUNKNOWN;
901 + frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO;
902 + frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
903 + frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
904 + frame_rec.timestamp.u64 = stream->timestamp.u64;
906 + status = stream->rec_cb(stream->user_data, &frame_rec);
907 + if (status != PJ_SUCCESS)
908 + PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status));
910 + frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO;
911 + frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE;
912 + frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME;
913 + frame_play.timestamp.u64 = stream->timestamp.u64;
915 + status = (*stream->play_cb)(stream->user_data, &frame_play);
916 + if (status != PJ_SUCCESS) {
917 + PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status));
919 + memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE);
921 + ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play));
924 + PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!"));
925 + return PJ_EUNKNOWN;
929 + PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!"));
930 + return PJ_EUNKNOWN;
934 + stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
941 +PJ_THREAD_FUNC tapi_dev_thread(void *arg) {
942 + tapi_ctx *dev_ctx = streams[0].dev_ctx;
943 + pj_uint32_t sretval;
944 + struct pollfd fds[3];
946 + PJ_LOG(1,(THIS_FILE, "TAPI: thread starting..."));
948 + streams[0].run_flag = 1;
949 + streams[1].run_flag = 1;
951 + fds[0].fd = dev_ctx->dev_fd;
952 + fds[0].events = POLLIN;
953 + fds[1].fd = dev_ctx->ch_fd[0];
954 + fds[1].events = POLLIN;
955 + fds[2].fd = dev_ctx->ch_fd[1];
956 + fds[2].events = POLLIN;
960 + sretval = poll(fds, TAPI_AUDIO_PORT_NUM + 1, TAPI_LL_DEV_SELECT_TIMEOUT_MS);
962 + if (!streams[0].run_flag && !streams[0].run_flag)
967 + if (fds[0].revents == POLLIN) {
968 + if (tapi_dev_event_handler(&streams[0]) != PJ_SUCCESS) {
969 + PJ_LOG(1, (THIS_FILE, "TAPI: event hanldler failed"));
974 + if (fds[1].revents == POLLIN) {
975 + if (tapi_dev_data_handler(&streams[0]) != PJ_SUCCESS) {
976 + PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
981 + if (fds[2].revents == POLLIN) {
982 + if (tapi_dev_data_handler(&streams[1]) != PJ_SUCCESS) {
983 + PJ_LOG(1, (THIS_FILE, "TAPI: data hanldler failed"));
988 + PJ_LOG(1, (THIS_FILE, "TAPI: thread stopping..."));
993 +/* Factory operations */
995 +pjmedia_aud_dev_factory*
996 +pjmedia_tapi_factory(pj_pool_factory *pf) {
997 + struct tapi_aud_factory *f;
1000 + TRACE_((THIS_FILE, "pjmedia_tapi_factory()"));
1002 + pool = pj_pool_create(pf, "tapi", 512, 512, NULL);
1003 + f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory);
1006 + f->base.op = &tapi_fact_op;
1012 +factory_init(pjmedia_aud_dev_factory *f)
1014 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1017 + TRACE_((THIS_FILE, "factory_init()"));
1019 + af->dev_count = TAPI_AUDIO_PORT_NUM;
1020 + af->dev_info = (pjmedia_aud_dev_info*)
1021 + pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info));
1022 + for (i = 0; i < TAPI_AUDIO_PORT_NUM; i++) {
1023 + pj_ansi_sprintf(af->dev_info[i].name,"%s_%02d", TAPI_BASE_NAME, i);
1024 + af->dev_info[i].input_count = af->dev_info[i].output_count = 1;
1025 + af->dev_info[i].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC;
1026 + pj_ansi_strcpy(af->dev_info[i].driver, "/dev/vmmc");
1027 + af->dev_info[i].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
1028 + PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
1029 + PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1030 + af->dev_info[i].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ;
1032 + if (tapi_dev_start(af) != PJ_SUCCESS) {
1033 + TRACE_((THIS_FILE, "ERROR - TAPI device init failed!"));
1034 + return PJ_EUNKNOWN;
1037 + return PJ_SUCCESS;
1041 +factory_destroy(pjmedia_aud_dev_factory *f)
1043 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1045 + pj_status_t status = PJ_SUCCESS;
1047 + TRACE_((THIS_FILE, "factory_destroy()"));
1049 + if (tapi_dev_stop(af) != PJ_SUCCESS) {
1050 + TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!"));
1051 + status = PJ_EUNKNOWN;
1055 + pj_pool_release(pool);
1061 +factory_get_dev_count(pjmedia_aud_dev_factory *f)
1063 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1064 + TRACE_((THIS_FILE, "factory_get_dev_count()"));
1066 + return af->dev_count;
1070 +factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_dev_info *info)
1072 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1074 + TRACE_((THIS_FILE, "factory_get_dev_info()"));
1075 + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1077 + pj_memcpy(info, &af->dev_info[index], sizeof(*info));
1079 + return PJ_SUCCESS;
1083 +factory_default_param(pjmedia_aud_dev_factory *f, unsigned index, pjmedia_aud_param *param)
1085 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1086 + struct pjmedia_aud_dev_info *di = &af->dev_info[index];
1088 + TRACE_((THIS_FILE, "factory_default_param."));
1089 + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV);
1091 + pj_bzero(param, sizeof(*param));
1092 + if (di->input_count && di->output_count) {
1093 + param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
1094 + param->rec_id = index;
1095 + param->play_id = index;
1096 + } else if (di->input_count) {
1097 + param->dir = PJMEDIA_DIR_CAPTURE;
1098 + param->rec_id = index;
1099 + param->play_id = PJMEDIA_AUD_INVALID_DEV;
1100 + } else if (di->output_count) {
1101 + param->dir = PJMEDIA_DIR_PLAYBACK;
1102 + param->play_id = index;
1103 + param->rec_id = PJMEDIA_AUD_INVALID_DEV;
1105 + return PJMEDIA_EAUD_INVDEV;
1108 + param->clock_rate = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec;
1109 + param->channel_count = 1;
1110 + param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME;
1111 + param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS;
1112 + param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps;
1113 + param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
1115 + return PJ_SUCCESS;
1120 +factory_create_stream(pjmedia_aud_dev_factory *f, const pjmedia_aud_param *param,
1121 + pjmedia_aud_rec_cb rec_cb, pjmedia_aud_play_cb play_cb,
1122 + void *user_data, pjmedia_aud_stream **p_aud_strm)
1124 + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f;
1126 + pj_status_t status;
1127 + int id = param->rec_id;
1128 + struct tapi_aud_stream *strm = &streams[param->rec_id];
1129 + TRACE_((THIS_FILE, "factory_create_stream() rec_id:%d play_id:%d", param->rec_id, param->play_id));
1131 + /* Can only support 16bits per sample */
1132 + PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL);
1133 + PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL);
1134 + PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL);
1136 + /* Can only support bidirectional stream */
1137 + PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL);
1140 + /* Initialize our stream data */
1141 + pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL);
1142 + PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
1144 + strm->pool = pool;
1146 + pool = strm->pool = streams[0].pool;
1149 + strm->rec_cb = rec_cb;
1150 + strm->play_cb = play_cb;
1151 + strm->user_data = user_data;
1153 + pj_memcpy(&strm->param, param, sizeof(*param));
1155 + if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) {
1156 + strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
1159 + strm->timestamp.u64 = 0;
1160 + strm->dev_ctx = &(af->dev_ctx);
1162 + /* Create and start the thread */
1164 + status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, &streams[0].thread);
1165 + if (status != PJ_SUCCESS) {
1166 + stream_destroy(&strm->base);
1172 + strm->base.op = &tapi_strm_op;
1173 + *p_aud_strm = &strm->base;
1175 + return PJ_SUCCESS;
1179 +stream_get_param(pjmedia_aud_stream *s, pjmedia_aud_param *pi)
1181 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1183 + PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1184 + pj_memcpy(pi, &strm->param, sizeof(*pi));
1186 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1187 + &pi->output_vol) == PJ_SUCCESS)
1188 + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1190 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
1191 + &pi->output_latency_ms) == PJ_SUCCESS)
1192 + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
1194 + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
1195 + &pi->input_latency_ms) == PJ_SUCCESS)
1196 + pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
1198 + return PJ_SUCCESS;
1202 +stream_get_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, void *pval)
1204 + // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1205 + return PJ_SUCCESS;
1209 +stream_set_cap(pjmedia_aud_stream *s, pjmedia_aud_dev_cap cap, const void *pval)
1211 + // struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1212 + return PJ_SUCCESS;
1216 +stream_start(pjmedia_aud_stream *s)
1218 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1219 + pj_uint32_t dev_idx;
1221 + TRACE_((THIS_FILE, "stream_start()"));
1223 + dev_idx = strm->param.rec_id;
1225 + return PJ_SUCCESS;
1229 +stream_stop(pjmedia_aud_stream *s)
1231 + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s;
1232 + tapi_ctx *dev_ctx = strm->dev_ctx;
1233 + pj_uint32_t dev_idx;
1235 + TRACE_((THIS_FILE, "stream_stop()"));
1236 + dev_idx = strm->param.rec_id;
1238 + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) {
1239 + TRACE_((THIS_FILE, "ERROR - codec start failed!"));
1240 + return PJ_EUNKNOWN;
1243 + return PJ_SUCCESS;
1247 +stream_destroy(pjmedia_aud_stream *s)
1249 + pj_status_t state = PJ_SUCCESS;
1250 + struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s;
1253 + PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
1254 + TRACE_((THIS_FILE, "stream_destroy()"));
1256 + stream_stop(&stream->base);
1257 + stream->run_flag = 0;
1259 + if (stream->thread)
1261 + pj_thread_join(stream->thread);
1262 + pj_thread_destroy(stream->thread);
1263 + stream->thread = NULL;
1266 + pool = stream->pool;
1267 + pj_bzero(stream, sizeof(stream));
1268 + pj_pool_release(pool);
1274 +tapi_hook_status(pj_uint8_t port, pj_int32_t *status)
1276 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1278 + if (ioctl(ch_fd[port], IFX_TAPI_LINE_HOOK_STATUS_GET, status)
1280 + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_HOOK_STATUS_GET ioctl failed!"));
1281 + return PJ_EUNKNOWN;
1284 + return PJ_SUCCESS;
1288 +tapi_ring(pj_uint8_t port, pj_uint8_t state, char *caller_number)
1290 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1293 + if (tapi_cid_type && caller_number) {
1294 + IFX_TAPI_CID_MSG_t cid_msg;
1295 + IFX_TAPI_CID_MSG_ELEMENT_t cid_msg_el[1];
1296 + memset(&cid_msg, 0, sizeof(cid_msg));
1297 + memset(&cid_msg_el, 0, sizeof(cid_msg_el));
1299 + cid_msg_el[0].string.elementType = IFX_TAPI_CID_ST_CLI;
1300 + cid_msg_el[0].string.len = strlen(caller_number);
1301 + strncpy(cid_msg_el[0].string.element, caller_number, sizeof(cid_msg_el[0].string.element));
1303 + cid_msg.txMode = IFX_TAPI_CID_HM_ONHOOK;
1304 + cid_msg.messageType = IFX_TAPI_CID_MT_CSUP;
1305 + cid_msg.nMsgElements = 1;
1306 + cid_msg.message = cid_msg_el;
1307 + ioctl(ch_fd[port], IFX_TAPI_CID_TX_SEQ_START, &cid_msg);
1309 + ioctl(ch_fd[port], IFX_TAPI_RING_START, 0);
1312 + ioctl(ch_fd[port], IFX_TAPI_RING_STOP, 0);
1315 + return PJ_SUCCESS;
1319 +tapi_tone(pj_uint8_t port, pj_uint8_t code)
1321 + PJ_ASSERT_RETURN(port < TAPI_AUDIO_PORT_NUM, PJ_EINVAL);
1323 + if (tapi_locale && code)
1324 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, code);
1326 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, TAPI_TONE_LOCALE_NONE);
1328 + ioctl(ch_fd[port], IFX_TAPI_TONE_LOCAL_PLAY, 0);
1330 + return PJ_SUCCESS;
1333 +#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */