blob: ba4e33edbc3a3fad864d4477f3dadecc7d4f6140 [file] [log] [blame]
/*****************************************************************************
** °æÈ¨ËùÓÐ (C)2015, ÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£
**
** ÎļþÃû³Æ: voice_buffer.c
** Îļþ±êʶ:
** ÄÚÈÝÕªÒª:
** ʹÓ÷½·¨:
**
** ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ Ð޸ıê¼Ç ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ
** -----------------------------------------------------------------------------
** 2023/07/18 V1.0 Create xxq ´´½¨
**
* ******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <poll.h>
#include <pthread.h>
#include <semaphore.h>
#include <linux/volte_drv.h>
//#define VB_DATA_LOSS_TEST
#define VB_MAX_INT 0x7fffffff
#define VB_MIN_INT 0 //(0-2<<31)//
#define VB_INT_OVERFLOW(x) if((x < VB_MIN_INT)||(x > VB_MAX_INT)) x = 0;
#define _TX_RX_DATA_FROM_FILE //test use
#define VB_FUNC_DEBUG //DEBUG use
#define VBUFFER_DEV_NAME "/dev/voice_buffer_dev"
#define VBUFFER_DEV_FLAGS O_RDWR //O_RDWR | O_SYNC
typedef int (vb_thread_proc)(void*);
typedef int (vb_ext_rx_tx_func)(void*,int);
struct vb_info_t
{
int fd;
pthread_t rx_thread;
pthread_t tx_thread;
int quit;
char *tx_buf;
char *rx_buf;
int buf_size;
vb_ext_rx_tx_func *ext_rx_func;
vb_ext_rx_tx_func *ext_tx_func;
sem_t read_sem;
sem_t write_sem;
#ifdef _TX_RX_DATA_FROM_FILE
char *tx_filename;
char *rx_filename;
FILE *tx_file;
FILE *rx_file;
int tx_filesize;
int rx_filesize;
#endif
};
struct vb_info_t vb_rec = {0};
int tx_optcount = 0;
int rx_optcount = 0;
int first_rderr_flag = 0;
int first_wrerr_flag = 0;
void vb_signal_back_func(int signum)
{
sem_post(&vb_rec.read_sem);
sem_post(&vb_rec.write_sem);
}
int voice_buffer_open(void)
{
int fd;
int oflags;
fd = open(VBUFFER_DEV_NAME, VBUFFER_DEV_FLAGS);
printf("%s: fd=%d!\n", __func__, fd);
signal(SIGIO, vb_signal_back_func); //Ó¦ÓóÌÐò×¢²áÐźŴ¦Àíº¯Êý£¬SIGIO±íʾIOÓÐÊý¾Ý¿É¹©¶ÁÈ¡
fcntl(fd, F_SETOWN, getpid());
oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags|FASYNC);
sem_init(&vb_rec.read_sem, 0, 0);
sem_init(&vb_rec.write_sem, 0, 0);
tx_optcount = 0;
rx_optcount = 0;
first_rderr_flag = 0;
first_wrerr_flag = 0;
return fd;
}
int voice_buffer_close(int fd)
{
int ret = 0;
if(fd >= 0){
ret = close(fd);
}
else{
printf("%s: fd invalid, return!\n", __func__);
return -ENOENT;
}
vb_rec.fd = -1;
sem_destroy(&vb_rec.read_sem);
sem_destroy(&vb_rec.write_sem);
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);
return ret;
}
int voice_buffer_write(int fd, unsigned char *pdata, unsigned int len)
{
int ret;
static struct timespec pre_wtime = {0};
struct timespec cur_wtime = {0};
if(fd >= 0){
sem_wait(&vb_rec.write_sem);
clock_gettime(CLOCK_REALTIME, &cur_wtime);
//printf("%s: tv_sec=%d, tv_nsec=%d\r\n", __func__, cur_wtime.tv_sec, cur_wtime.tv_nsec);
ret = write(fd, pdata, len);
}
else{
printf("%s: fd invalid, return!\n",__func__);
return -ENOENT;
}
return ret;
}
int voice_buffer_read(int fd, unsigned char *pdata, unsigned int len)
{
int ret;
static struct timespec pre_rtime = {0};
struct timespec cur_rtime = {0};
if(fd >= 0){
sem_wait(&vb_rec.read_sem);
clock_gettime(CLOCK_REALTIME, &cur_rtime);
//printf("%s: tv_sec=%d, tv_nsec=%d\r\n", __func__, cur_rtime.tv_sec, cur_rtime.tv_nsec);
ret = read(fd, pdata, len);
}
else{
printf("%s: fd invalid, return!\n", __func__);
return -ENOENT;
}
return ret;
}
int voice_buffer_ioctl(int fd, unsigned int cmd, void *pvalue)
{
int ret = 0;
if(fd >= 0){
ret = ioctl(fd, cmd, pvalue);
}
else{
printf("%s: fd invalid, return\n", __func__);
return -ENOENT;
}
return ret;
}
static int vb_rx_thread_func(void *arg)
{
int ret = 0;
char* buf = vb_rec.rx_buf;
int size = vb_rec.buf_size;
unsigned int bytes_read = 0;
int r_size = 0;
printf("%s: start size=%d!\n", __func__, size);
memset(buf, 0, size);
while(!vb_rec.quit){
rx_optcount ++;
VB_INT_OVERFLOW(rx_optcount);
if((rx_optcount % 1000) == 0){
printf("%s: rx_optcount=%d!\n", __func__, rx_optcount);
if(rx_optcount == 1000000)
rx_optcount = 0;
}
//read from ps
r_size = voice_buffer_read(vb_rec.fd, buf, size);
if(r_size <= 0){
first_rderr_flag++;
VB_INT_OVERFLOW(first_rderr_flag);
if(first_rderr_flag == 1){
printf( "%s: error reading data!\n", __func__);
}
if((first_rderr_flag % 500) == 0){
printf("%s: first_rderr_flag=%d!\n", __func__, first_rderr_flag);
}
continue ;
}
else{
first_rderr_flag = 0;
}
#ifdef _TX_RX_DATA_FROM_FILE
if(vb_rec.rx_file != NULL)
{
#if 0
static int i=0;
i++;
if (i==50) {
printf("vb_rx_thread_func buf[%d]=%d\n",i,buf[i]);
i=0;
}
#endif
//if(fwrite(buf, 1, size, vb_rec.rx_file) != size){//µ¥¸ö×Ö½ÚдÈ룬ÎļþûÊý¾Ý
if(fwrite(buf, size, 1, vb_rec.rx_file) != 1){
printf("%s: Error fwrite\n", __func__);
//break;
}
else{
bytes_read += size;
if(bytes_read >= vb_rec.rx_filesize){
//fseek(vb_rec.rx_file, 0, SEEK_SET);//дÈë²»ÏÞÖÆÎļþ´óС
}
}
}
#endif
}
return 0;
}
static int vb_tx_thread_func(void *arg)
{
int ret = 0;
int num_read = 0;
char* buf = vb_rec.tx_buf;
int size = vb_rec.buf_size;
int w_size = 0;
printf("%s: start size=%d!\n", __func__, size);
#ifndef VB_DATA_LOSS_TEST
memset(buf, 0, size);
#endif
while(!vb_rec.quit){
#if defined (_TX_RX_DATA_FROM_FILE) && !defined (VB_DATA_LOSS_TEST)
if(vb_rec.tx_file != NULL)
{
//num_read = fread(buf, 1, size, vb_rec.tx_file);
num_read = fread(buf, size, 1, vb_rec.tx_file);
if (num_read <= 0) {
printf("%s: vb_rec.tx_file read end\n",__func__);
// no data
//fseek(vb_rec.tx_file, 0, SEEK_SET);
}
}
#endif
tx_optcount ++;
VB_INT_OVERFLOW(tx_optcount);
if((tx_optcount%1000) == 0){
printf("%s: tx_optcount=%d!\n", __func__, tx_optcount);
if(tx_optcount == 1000000)
tx_optcount = 0;
}
//write to ps
w_size = voice_buffer_write(vb_rec.fd, buf, size);
if(w_size <= 0){
first_wrerr_flag++;
VB_INT_OVERFLOW(first_wrerr_flag);
if(first_wrerr_flag ==1){
printf("%s: error writing data!\n", __func__);
}
if((first_wrerr_flag % 500) == 0){
printf("%s: first_wrerr_flag=%d!\n", __func__, first_wrerr_flag);
}
continue;
}
else{
first_wrerr_flag = 0;
}
}
return 0;
}
static int vb_thread_create( const char *name,pthread_t *thread_t, vb_thread_proc *proc,
int stack_size, unsigned priority,void *arg )
{
pthread_attr_t thread_attr;
int ret = 0;
int default_size = 0;
struct sched_param param;
int policy = SCHED_FIFO;
/* Set default stack size */
//stack_size = 8*1024;//32*1024;
printf("%s: start!\n", __func__);
/* Init thread attributes */
pthread_attr_init(&thread_attr);
//pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
/*
ret = pthread_attr_setstacksize(&thread_attr, stack_size);
if (ret != 0)
{
printf("%s: pthread_attr_setstacksize(%d) fail,ret=%d! \n",__func__,stack_size,ret);
pthread_attr_destroy(&thread_attr);
return ret;
}
*/
/* Create the thread. */
ret = pthread_create( thread_t, &thread_attr,proc, arg);
if(ret != 0){
printf("%s: pthread_create fail,ret=%d!\n", __func__, ret);
pthread_attr_destroy(&thread_attr);
return ret;
}
pthread_attr_getstacksize(&thread_attr, &default_size);
printf("%s: pthread_attr_getstacksize(%d)!\n", __func__, default_size);
//pthread_detach(rec->thread);
/*
memset(&param, 0, sizeof(param));
//param.sched_priority =36;
param.sched_priority = priority;
pthread_setschedparam(thread_t, policy, &param);
*/
pthread_attr_destroy(&thread_attr);
printf("%s: end\n", __func__);
return 0;
}
//Start stream
int vbuffer_stream_start(void)
{
int ret = 0;
//voice_buffer_open
int fs = 0;
int buf_size = 0;
printf("Starting vb stream\n");
tx_optcount = 0;
rx_optcount = 0;
int* buf_int;
int i = 0;
vb_rec.fd = voice_buffer_open();
if(vb_rec.fd < 0){
printf("%s: vb open fail, fd=%d\n", __func__, vb_rec.fd);
ret = -1;
goto err;
}
ret = ioctl(vb_rec.fd, VOICE_IOCTL_GET_FS, &fs);
if(ret){
printf("%s: VOICE_IOCTL_GET_FS fd=%d,ret=%d.\n", __func__, vb_rec.fd, ret);
goto err;
}
if(8000 == fs)
buf_size = 320;
else if(16000 == fs)
buf_size = 640;
else{
buf_size = 0;
printf("%s: fs is error, buf_size=%d\n", __func__, buf_size);
goto err;
}
#ifdef _TX_RX_DATA_FROM_FILE
printf("%s: open tx and rx file\n", __func__);
if(8000 == fs)
vb_rec.tx_filename = "/mnt/userdata/tx8.pcm";
else if(16000 == fs)
vb_rec.tx_filename = "/mnt/userdata/tx16.pcm";
vb_rec.tx_file = fopen(vb_rec.tx_filename, "rb");
if(!vb_rec.tx_file){
printf("Unable to open file '%s'\n", vb_rec.tx_filename);
//return 1;
}
if(8000 == fs)
vb_rec.rx_filename = "/mnt/userdata/rx8.pcm";
else if(16000 == fs)
vb_rec.rx_filename = "/mnt/userdata/rx16.pcm";
vb_rec.rx_file = fopen(vb_rec.rx_filename, "wb");
if(!vb_rec.rx_file){
printf(stderr, "Unable to create file '%s'\n", vb_rec.rx_filename);
//return 1;
}
vb_rec.rx_filesize = 0x10000;
//vb_rec.buf_size = buf_size;
#endif
vb_rec.rx_buf = (char*)malloc(buf_size);
if(!vb_rec.rx_buf){
printf("%s: malloc rx_buf fail\n", __func__);
goto err;
}
vb_rec.tx_buf = (char*)malloc(buf_size);
if(!vb_rec.tx_buf){
//free(vb_rec.rx_buf);
printf("%s: malloc tx_buf fail\n", __func__);
goto err;
}
vb_rec.buf_size = buf_size;
#ifdef VB_DATA_LOSS_TEST//for test
buf_int = (int*)vb_rec.tx_buf;
for(i = 0; i < (buf_size / 4); i++){
*(buf_int + i) = i;
//buf_int[i] = i;
if(i > 0x1f)
printf("cap user: *(buf_int+%d)=%d\n", i, *(buf_int+i));
}
#endif
vb_rec.quit = 0;
printf("%s: rx tx vb_thread_create start\n", __func__);
ret = vb_thread_create("vb_playback", &vb_rec.rx_thread, vb_rx_thread_func,
4*1024, 36, NULL);
if(ret != 0){
printf("%s: rx vb_thread_create fail ret=%d\n", __func__, ret);
goto err;
}
printf("%s: rx vb_thread_create end\n", __func__);
ret = vb_thread_create("vb_record", &vb_rec.tx_thread, vb_tx_thread_func,
4*1024, 36, NULL);
if(ret != 0){
printf("%s: tx vb_thread_create fail ret=%d\n", __func__, ret);
vb_rec.quit = 1;
pthread_join(vb_rec.rx_thread,NULL);
vb_rec.rx_thread = NULL;
goto err;
}
printf("%s: tx vb_thread_create end\n", __func__);
//vb_rec.quit = 0;
return 0;
err:
if(vb_rec.rx_buf != NULL)
free(vb_rec.rx_buf);
if(vb_rec.tx_buf != NULL)
free(vb_rec.tx_buf);
if(vb_rec.fd >= 0)
voice_buffer_close(vb_rec.fd);
return ret;
}
//Stop stream
int vbuffer_stream_stop(void)
{
int ret = 0;
printf("%s: rx tx thread exit start\n", __func__);
vb_rec.quit = 1;
sem_post(&vb_rec.read_sem);
sem_post(&vb_rec.write_sem);
if(vb_rec.tx_thread){
pthread_join (vb_rec.tx_thread,NULL);
vb_rec.tx_thread = NULL;
printf("tx_thread exit end\n");
}
if(vb_rec.rx_thread){
pthread_join (vb_rec.rx_thread,NULL);
vb_rec.rx_thread = NULL;
printf("rx_thread exit end\n");
}
printf("%s: voice_buffer_close start\n", __func__);
ret = voice_buffer_close(vb_rec.fd);
if(ret != 0){
printf("%s: vb close fail\n", __func__);
return -1;
}
#ifdef _TX_RX_DATA_FROM_FILE
if(vb_rec.tx_file != NULL){
fclose(vb_rec.tx_file);
printf("%s: vb close, close tx file\n", __func__);
}
if(vb_rec.rx_file != NULL){
fclose(vb_rec.rx_file);
printf("%s: vb close, close rx file\n", __func__);
}
#endif
printf("Stopping vb stream end\n");
return 0;
}