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