blob: ba4e33edbc3a3fad864d4477f3dadecc7d4f6140 [file] [log] [blame]
xf.lie31de8b2023-12-26 23:38:58 -08001/*****************************************************************************
2** °æÈ¨ËùÓÐ (C)2015, ÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£
3**
4** ÎļþÃû³Æ: voice_buffer.c
5** Îļþ±êʶ:
6** ÄÚÈÝÕªÒª:
7** ʹÓ÷½·¨:
8**
9** ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ Ð޸ıê¼Ç ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ
10** -----------------------------------------------------------------------------
11** 2023/07/18 V1.0 Create xxq ´´½¨
12**
13* ******************************************************************************/
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <assert.h>
18#include <errno.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <stdint.h>
25
26#include <fcntl.h>
27#include <sys/ioctl.h>
28#include <signal.h>
29
30#include <poll.h>
31#include <pthread.h>
32#include <semaphore.h>
33
34#include <linux/volte_drv.h>
35
36//#define VB_DATA_LOSS_TEST
37
38#define VB_MAX_INT 0x7fffffff
39#define VB_MIN_INT 0 //(0-2<<31)//
40#define VB_INT_OVERFLOW(x) if((x < VB_MIN_INT)||(x > VB_MAX_INT)) x = 0;
41
42#define _TX_RX_DATA_FROM_FILE //test use
43#define VB_FUNC_DEBUG //DEBUG use
44
45#define VBUFFER_DEV_NAME "/dev/voice_buffer_dev"
46#define VBUFFER_DEV_FLAGS O_RDWR //O_RDWR | O_SYNC
47
48typedef int (vb_thread_proc)(void*);
49typedef int (vb_ext_rx_tx_func)(void*,int);
50
51struct vb_info_t
52{
53 int fd;
54 pthread_t rx_thread;
55 pthread_t tx_thread;
56 int quit;
57 char *tx_buf;
58 char *rx_buf;
59 int buf_size;
60 vb_ext_rx_tx_func *ext_rx_func;
61 vb_ext_rx_tx_func *ext_tx_func;
62 sem_t read_sem;
63 sem_t write_sem;
64#ifdef _TX_RX_DATA_FROM_FILE
65 char *tx_filename;
66 char *rx_filename;
67 FILE *tx_file;
68 FILE *rx_file;
69 int tx_filesize;
70 int rx_filesize;
71#endif
72};
73
74struct vb_info_t vb_rec = {0};
75
76int tx_optcount = 0;
77int rx_optcount = 0;
78int first_rderr_flag = 0;
79int first_wrerr_flag = 0;
80
81void vb_signal_back_func(int signum)
82{
83 sem_post(&vb_rec.read_sem);
84 sem_post(&vb_rec.write_sem);
85}
86
87int voice_buffer_open(void)
88{
89 int fd;
90 int oflags;
91
92 fd = open(VBUFFER_DEV_NAME, VBUFFER_DEV_FLAGS);
93 printf("%s: fd=%d!\n", __func__, fd);
94
95 signal(SIGIO, vb_signal_back_func); //Ó¦ÓóÌÐò×¢²áÐźŴ¦Àíº¯Êý£¬SIGIO±íʾIOÓÐÊý¾Ý¿É¹©¶ÁÈ¡
96 fcntl(fd, F_SETOWN, getpid());
97 oflags = fcntl(fd, F_GETFL);
98 fcntl(fd, F_SETFL, oflags|FASYNC);
99
100 sem_init(&vb_rec.read_sem, 0, 0);
101 sem_init(&vb_rec.write_sem, 0, 0);
102
103 tx_optcount = 0;
104 rx_optcount = 0;
105
106 first_rderr_flag = 0;
107 first_wrerr_flag = 0;
108
109 return fd;
110}
111
112int voice_buffer_close(int fd)
113{
114 int ret = 0;
115
116 if(fd >= 0){
117 ret = close(fd);
118 }
119 else{
120 printf("%s: fd invalid, return!\n", __func__);
121 return -ENOENT;
122 }
123
124 vb_rec.fd = -1;
125 sem_destroy(&vb_rec.read_sem);
126 sem_destroy(&vb_rec.write_sem);
127 printf("%s, first_rderr_flag=%d, first_wrerr_flag=%d, tx_optcount=%d, rx_optcount=%d\n", __func__, first_rderr_flag, first_wrerr_flag, tx_optcount, rx_optcount);
128
129 return ret;
130}
131
132
133int voice_buffer_write(int fd, unsigned char *pdata, unsigned int len)
134{
135 int ret;
136 static struct timespec pre_wtime = {0};
137 struct timespec cur_wtime = {0};
138
139 if(fd >= 0){
140 sem_wait(&vb_rec.write_sem);
141 clock_gettime(CLOCK_REALTIME, &cur_wtime);
142 //printf("%s: tv_sec=%d, tv_nsec=%d\r\n", __func__, cur_wtime.tv_sec, cur_wtime.tv_nsec);
143
144 ret = write(fd, pdata, len);
145 }
146 else{
147 printf("%s: fd invalid, return!\n",__func__);
148 return -ENOENT;
149 }
150 return ret;
151}
152
153int voice_buffer_read(int fd, unsigned char *pdata, unsigned int len)
154{
155 int ret;
156 static struct timespec pre_rtime = {0};
157 struct timespec cur_rtime = {0};
158
159 if(fd >= 0){
160 sem_wait(&vb_rec.read_sem);
161 clock_gettime(CLOCK_REALTIME, &cur_rtime);
162 //printf("%s: tv_sec=%d, tv_nsec=%d\r\n", __func__, cur_rtime.tv_sec, cur_rtime.tv_nsec);
163
164 ret = read(fd, pdata, len);
165 }
166 else{
167 printf("%s: fd invalid, return!\n", __func__);
168 return -ENOENT;
169 }
170
171 return ret;
172}
173
174int voice_buffer_ioctl(int fd, unsigned int cmd, void *pvalue)
175{
176 int ret = 0;
177
178 if(fd >= 0){
179 ret = ioctl(fd, cmd, pvalue);
180 }
181 else{
182 printf("%s: fd invalid, return\n", __func__);
183 return -ENOENT;
184 }
185
186 return ret;
187}
188
189static int vb_rx_thread_func(void *arg)
190{
191 int ret = 0;
192
193 char* buf = vb_rec.rx_buf;
194 int size = vb_rec.buf_size;
195 unsigned int bytes_read = 0;
196 int r_size = 0;
197
198 printf("%s: start size=%d!\n", __func__, size);
199 memset(buf, 0, size);
200
201 while(!vb_rec.quit){
202 rx_optcount ++;
203 VB_INT_OVERFLOW(rx_optcount);
204
205 if((rx_optcount % 1000) == 0){
206 printf("%s: rx_optcount=%d!\n", __func__, rx_optcount);
207
208 if(rx_optcount == 1000000)
209 rx_optcount = 0;
210 }
211
212 //read from ps
213 r_size = voice_buffer_read(vb_rec.fd, buf, size);
214
215 if(r_size <= 0){
216 first_rderr_flag++;
217
218 VB_INT_OVERFLOW(first_rderr_flag);
219
220 if(first_rderr_flag == 1){
221 printf( "%s: error reading data!\n", __func__);
222 }
223 if((first_rderr_flag % 500) == 0){
224 printf("%s: first_rderr_flag=%d!\n", __func__, first_rderr_flag);
225 }
226
227 continue ;
228 }
229 else{
230 first_rderr_flag = 0;
231 }
232
233#ifdef _TX_RX_DATA_FROM_FILE
234 if(vb_rec.rx_file != NULL)
235 {
236#if 0
237 static int i=0;
238 i++;
239 if (i==50) {
240 printf("vb_rx_thread_func buf[%d]=%d\n",i,buf[i]);
241 i=0;
242 }
243#endif
244 //if(fwrite(buf, 1, size, vb_rec.rx_file) != size){//µ¥¸ö×Ö½ÚдÈ룬ÎļþûÊý¾Ý
245 if(fwrite(buf, size, 1, vb_rec.rx_file) != 1){
246 printf("%s: Error fwrite\n", __func__);
247 //break;
248 }
249 else{
250 bytes_read += size;
251
252 if(bytes_read >= vb_rec.rx_filesize){
253 //fseek(vb_rec.rx_file, 0, SEEK_SET);//дÈë²»ÏÞÖÆÎļþ´óС
254 }
255 }
256 }
257#endif
258 }
259
260 return 0;
261}
262
263static int vb_tx_thread_func(void *arg)
264{
265 int ret = 0;
266
267 int num_read = 0;
268 char* buf = vb_rec.tx_buf;
269 int size = vb_rec.buf_size;
270 int w_size = 0;
271
272 printf("%s: start size=%d!\n", __func__, size);
273
274#ifndef VB_DATA_LOSS_TEST
275 memset(buf, 0, size);
276#endif
277
278 while(!vb_rec.quit){
279#if defined (_TX_RX_DATA_FROM_FILE) && !defined (VB_DATA_LOSS_TEST)
280
281 if(vb_rec.tx_file != NULL)
282 {
283 //num_read = fread(buf, 1, size, vb_rec.tx_file);
284 num_read = fread(buf, size, 1, vb_rec.tx_file);
285 if (num_read <= 0) {
286 printf("%s: vb_rec.tx_file read end\n",__func__);
287 // no data
288 //fseek(vb_rec.tx_file, 0, SEEK_SET);
289 }
290 }
291#endif
292
293 tx_optcount ++;
294 VB_INT_OVERFLOW(tx_optcount);
295
296 if((tx_optcount%1000) == 0){
297 printf("%s: tx_optcount=%d!\n", __func__, tx_optcount);
298
299 if(tx_optcount == 1000000)
300 tx_optcount = 0;
301 }
302
303 //write to ps
304 w_size = voice_buffer_write(vb_rec.fd, buf, size);
305
306 if(w_size <= 0){
307 first_wrerr_flag++;
308 VB_INT_OVERFLOW(first_wrerr_flag);
309
310 if(first_wrerr_flag ==1){
311 printf("%s: error writing data!\n", __func__);
312 }
313 if((first_wrerr_flag % 500) == 0){
314 printf("%s: first_wrerr_flag=%d!\n", __func__, first_wrerr_flag);
315 }
316
317 continue;
318 }
319 else{
320 first_wrerr_flag = 0;
321 }
322 }
323
324 return 0;
325}
326
327static int vb_thread_create( const char *name,pthread_t *thread_t, vb_thread_proc *proc,
328 int stack_size, unsigned priority,void *arg )
329{
330 pthread_attr_t thread_attr;
331 int ret = 0;
332 int default_size = 0;
333
334 struct sched_param param;
335 int policy = SCHED_FIFO;
336
337 /* Set default stack size */
338 //stack_size = 8*1024;//32*1024;
339 printf("%s: start!\n", __func__);
340
341 /* Init thread attributes */
342 pthread_attr_init(&thread_attr);
343 //pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
344 /*
345 ret = pthread_attr_setstacksize(&thread_attr, stack_size);
346 if (ret != 0)
347 {
348
349 printf("%s: pthread_attr_setstacksize(%d) fail,ret=%d! \n",__func__,stack_size,ret);
350 pthread_attr_destroy(&thread_attr);
351 return ret;
352 }
353 */
354
355 /* Create the thread. */
356
357 ret = pthread_create( thread_t, &thread_attr,proc, arg);
358 if(ret != 0){
359 printf("%s: pthread_create fail,ret=%d!\n", __func__, ret);
360
361 pthread_attr_destroy(&thread_attr);
362
363 return ret;
364 }
365
366 pthread_attr_getstacksize(&thread_attr, &default_size);
367 printf("%s: pthread_attr_getstacksize(%d)!\n", __func__, default_size);
368
369 //pthread_detach(rec->thread);
370 /*
371 memset(&param, 0, sizeof(param));
372 //param.sched_priority =36;
373 param.sched_priority = priority;
374 pthread_setschedparam(thread_t, policy, &param);
375 */
376 pthread_attr_destroy(&thread_attr);
377
378 printf("%s: end\n", __func__);
379
380 return 0;
381}
382
383//Start stream
384int vbuffer_stream_start(void)
385{
386 int ret = 0;
387
388 //voice_buffer_open
389 int fs = 0;
390 int buf_size = 0;
391 printf("Starting vb stream\n");
392 tx_optcount = 0;
393 rx_optcount = 0;
394 int* buf_int;
395 int i = 0;
396
397 vb_rec.fd = voice_buffer_open();
398 if(vb_rec.fd < 0){
399 printf("%s: vb open fail, fd=%d\n", __func__, vb_rec.fd);
400 ret = -1;
401 goto err;
402 }
403
404 ret = ioctl(vb_rec.fd, VOICE_IOCTL_GET_FS, &fs);
405 if(ret){
406 printf("%s: VOICE_IOCTL_GET_FS fd=%d,ret=%d.\n", __func__, vb_rec.fd, ret);
407 goto err;
408 }
409
410 if(8000 == fs)
411 buf_size = 320;
412 else if(16000 == fs)
413 buf_size = 640;
414 else{
415 buf_size = 0;
416 printf("%s: fs is error, buf_size=%d\n", __func__, buf_size);
417 goto err;
418 }
419
420#ifdef _TX_RX_DATA_FROM_FILE
421 printf("%s: open tx and rx file\n", __func__);
422
423 if(8000 == fs)
424 vb_rec.tx_filename = "/mnt/userdata/tx8.pcm";
425 else if(16000 == fs)
426 vb_rec.tx_filename = "/mnt/userdata/tx16.pcm";
427
428 vb_rec.tx_file = fopen(vb_rec.tx_filename, "rb");
429 if(!vb_rec.tx_file){
430 printf("Unable to open file '%s'\n", vb_rec.tx_filename);
431 //return 1;
432 }
433
434 if(8000 == fs)
435 vb_rec.rx_filename = "/mnt/userdata/rx8.pcm";
436 else if(16000 == fs)
437 vb_rec.rx_filename = "/mnt/userdata/rx16.pcm";
438
439 vb_rec.rx_file = fopen(vb_rec.rx_filename, "wb");
440 if(!vb_rec.rx_file){
441 printf(stderr, "Unable to create file '%s'\n", vb_rec.rx_filename);
442 //return 1;
443 }
444
445 vb_rec.rx_filesize = 0x10000;
446 //vb_rec.buf_size = buf_size;
447#endif
448
449 vb_rec.rx_buf = (char*)malloc(buf_size);
450 if(!vb_rec.rx_buf){
451 printf("%s: malloc rx_buf fail\n", __func__);
452 goto err;
453 }
454
455 vb_rec.tx_buf = (char*)malloc(buf_size);
456 if(!vb_rec.tx_buf){
457 //free(vb_rec.rx_buf);
458 printf("%s: malloc tx_buf fail\n", __func__);
459 goto err;
460 }
461
462 vb_rec.buf_size = buf_size;
463
464#ifdef VB_DATA_LOSS_TEST//for test
465 buf_int = (int*)vb_rec.tx_buf;
466
467 for(i = 0; i < (buf_size / 4); i++){
468 *(buf_int + i) = i;
469 //buf_int[i] = i;
470 if(i > 0x1f)
471 printf("cap user: *(buf_int+%d)=%d\n", i, *(buf_int+i));
472 }
473#endif
474
475 vb_rec.quit = 0;
476
477 printf("%s: rx tx vb_thread_create start\n", __func__);
478 ret = vb_thread_create("vb_playback", &vb_rec.rx_thread, vb_rx_thread_func,
479 4*1024, 36, NULL);
480 if(ret != 0){
481 printf("%s: rx vb_thread_create fail ret=%d\n", __func__, ret);
482 goto err;
483 }
484
485 printf("%s: rx vb_thread_create end\n", __func__);
486
487 ret = vb_thread_create("vb_record", &vb_rec.tx_thread, vb_tx_thread_func,
488 4*1024, 36, NULL);
489 if(ret != 0){
490 printf("%s: tx vb_thread_create fail ret=%d\n", __func__, ret);
491 vb_rec.quit = 1;
492 pthread_join(vb_rec.rx_thread,NULL);
493 vb_rec.rx_thread = NULL;
494 goto err;
495 }
496
497 printf("%s: tx vb_thread_create end\n", __func__);
498
499 //vb_rec.quit = 0;
500 return 0;
501
502err:
503 if(vb_rec.rx_buf != NULL)
504 free(vb_rec.rx_buf);
505
506 if(vb_rec.tx_buf != NULL)
507 free(vb_rec.tx_buf);
508
509 if(vb_rec.fd >= 0)
510 voice_buffer_close(vb_rec.fd);
511
512 return ret;
513}
514
515//Stop stream
516int vbuffer_stream_stop(void)
517{
518 int ret = 0;
519 printf("%s: rx tx thread exit start\n", __func__);
520
521 vb_rec.quit = 1;
522 sem_post(&vb_rec.read_sem);
523 sem_post(&vb_rec.write_sem);
524
525 if(vb_rec.tx_thread){
526 pthread_join (vb_rec.tx_thread,NULL);
527 vb_rec.tx_thread = NULL;
528 printf("tx_thread exit end\n");
529 }
530
531 if(vb_rec.rx_thread){
532 pthread_join (vb_rec.rx_thread,NULL);
533 vb_rec.rx_thread = NULL;
534 printf("rx_thread exit end\n");
535 }
536
537 printf("%s: voice_buffer_close start\n", __func__);
538 ret = voice_buffer_close(vb_rec.fd);
539 if(ret != 0){
540 printf("%s: vb close fail\n", __func__);
541
542 return -1;
543 }
544
545#ifdef _TX_RX_DATA_FROM_FILE
546 if(vb_rec.tx_file != NULL){
547 fclose(vb_rec.tx_file);
548 printf("%s: vb close, close tx file\n", __func__);
549 }
550
551 if(vb_rec.rx_file != NULL){
552 fclose(vb_rec.rx_file);
553 printf("%s: vb close, close rx file\n", __func__);
554 }
555#endif
556
557 printf("Stopping vb stream end\n");
558
559 return 0;
560}
561