linux usb mic延时大如何解决,LINUX下实时录放音(OSS)—解决时延有关问题

#include

#include

#include

#include

#include

#include

#include

#include

#define RATE 16000 //采样频率

#define SIZE 16 //量化位数

#define CHANNELS 1 //声道数目

#define RSIZE 80 //buf的大小,

int main(void)

{

int fd_dev_r;

int fd_dev_w;

int fd_f;

int arg;

int status;

char choice;

int i;

unsigned char buf[RSIZE]; //每次循环取得RSIZE大小的容量,放入buf,然后写入文件;

//打开声卡设备,只读方式;并对声卡进行设置

fd_dev_r= open("/dev/dsp", O_RDONLY,0777);

if (fd_dev_r < 0)

{

perror("Cannot open /dev/dsp device");

return 1;

}

arg = SIZE;

status = ioctl(fd_dev_r, SOUND_PCM_WRITE_BITS, &arg);//设置量化位数

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_BITS ");

return 1;

}

arg = CHANNELS;

status = ioctl(fd_dev_r, SOUND_PCM_WRITE_CHANNELS, &arg);//设置声道数

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_CHANNELS");

return 1;

}

arg = RATE;

status = ioctl(fd_dev_r, SOUND_PCM_WRITE_RATE, &arg);//设置采样率

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_WRITE");

return 1;

}

//打开声卡设备,只写方式;并对声卡进行设置

fd_dev_w = open("/dev/dsp", O_WRONLY,0777);

if (fd_dev_w < 0)

{

perror("Cannot open /dev/dsp device");

return 1;

}

arg = SIZE;

status = ioctl(fd_dev_w, SOUND_PCM_WRITE_BITS, &arg);//设置量化位数

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_BITS ");

return 1;

}

arg = CHANNELS;

status = ioctl(fd_dev_w, SOUND_PCM_WRITE_CHANNELS, &arg);//设置声道数

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_CHANNELS");

return 1;

}

arg = RATE;

status = ioctl(fd_dev_w, SOUND_PCM_WRITE_RATE, &arg);//设置采样率

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_WRITE");

return 1;

}

for(;;)

{

status = read(fd_dev_r, buf, sizeof(buf));

if (status != sizeof(buf))

{

perror("read wrong number of bytes");

}

status = write(fd_dev_w, buf, sizeof(buf));//送声卡播放

if (status != sizeof(buf))

perror("wrote2 wrong number of bytes");

}

close(fd_dev_r);//关闭只读方式的声卡

close(fd_dev_w);

return 0;

}

如果没有强制设置buffer大小,系统默认的缓冲buffer的大小是2*4096=8192字节,其中2表示的是fragement的数量,4096是每个fragementsize的大小。系统读取音频数据之后,放音的时候,先放入缓冲buffer中,当缓冲buffer填满时,系统才会产生中断,播放音频。所以这里会存在一个延迟。像系统默认的buffer大小,如果录制的是16khz 16bit的音频的话,延迟大小是就是2 * 4096 / (16000 * 2) = 256ms。如果程序要求实时性,就必须得修改buffer的大小。

在OSS的ioctl接口中,SNDCTL_DSP_SETFRAGMENT就是用来设置驱动程序内部缓冲区大小。具体的用法如下:(特别注意的是这个设置要放在所有设置之前,不然会出问题)

int param;

param = ( 0x0004 << 16) + 0x000a;

if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &param) == -1) {

...error handling...

}

参数param由两部分组成:低16位为fragment的大小,此处0x000a表示fragment大小为2^0xa,即1024字节;高16位为fragment的数量,此处为0x0004,即4个fragement。设置好fragment参数后,通过ioctl的SNDCTL_DSP_SETFRAGMENT命令调整驱动程序中的缓冲区。

如果你要查看系统的buffer的大小的话,也可以通过以下程序获得

int frag_size;

ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &frag_size)

也可以通过以下程序获得更详细的信息:

audio_buf_info info;

if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)

{

printf("SNDCTL_DSP_GETOSPACE error\n");

}

printf("bytes:%d fragments:%d fragsize:%d fragstotal:%d\n",info.bytes,info.fragments,info.fragsize,info.fragstotal);

解决时延的完成程序

#include

#include

#include

#include

#include

#include

#define DEVICE_NAME "/dev/dsp"

#include

#include

#define frame_size 80

int audio_fd;

int recoder_fid;

audio_buf_info info;

int main(int argc, char *argv[])

{

short int i;

short int tempVar;

int status;

int sampleRate = 16000; //16khz

int format = 16;

int channels = 1;

int frag_size= 0;

FILE *fp_in;

short int *SigBuf;

int FrameCounter=0;

char *read_mic_file = "read_from_mic.pcm";

printf("时延 (128*2)/(16000*2)= 8ms \n");

fp_in=fopen(read_mic_file,"wb");

recoder_fid = open(DEVICE_NAME, O_RDONLY,0777);

if (recoder_fid < 0)

{

perror("Cannot open /dev/dsp device");

return 1;

}

status = ioctl(recoder_fid, SOUND_PCM_WRITE_BITS, &format);//设置量化位数

if(status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_BITS ");

return 1;

}

status = ioctl(recoder_fid, SOUND_PCM_WRITE_CHANNELS, &channels);//设置声道数

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_CHANNELS");

return 1;

}

status = ioctl(recoder_fid, SOUND_PCM_WRITE_RATE, &sampleRate);//设置采样率

if (status == -1)

{

perror("Cannot set SOUND_PCM_WRITE_WRITE");

return 1;

}

if ((audio_fd = open(DEVICE_NAME, O_WRONLY,0777)) == -1)

{

printf("open error\n");

return -1;

}

if (ioctl(audio_fd, SOUND_PCM_WRITE_BITS, &format) == -1)

{

/* fatal error */

printf("SNDCTL_DSP_SETFMT error\n");

return -1;

}

int param;

param = ( 0x0002 << 16) + 0x0006; //参数param由两部分组成:低16位为fragment的大小,此处0x0007表示fragment大小为2^7,即128字节;

//高16位为fragment的数量,此处为0x0002,即2个fragement。

if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &param) == -1) {

printf("SNDCTL_DSP_SETFRAGMENT error\n");

}

if (ioctl(audio_fd, SOUND_PCM_WRITE_CHANNELS, &channels) == -1)

{

/* Fatal error */

printf("SOUND_PCM_WRITE_CHANNELS error");

return -1;

}

if (ioctl(audio_fd, SOUND_PCM_WRITE_RATE, &sampleRate)==-1)

{

/* Fatal error */

printf("SOUND_PCM_WRITE_RATE error\n");

return -1;

}

int version = 0;

if (ioctl(audio_fd, OSS_GETVERSION, &version) == -1) {

printf("Failed to get OSS version\n");

}

printf("OSS version is:%x \n",version);

ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &frag_size);

printf("fragment size is:%d \n",frag_size);

if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)

{

printf("SNDCTL_DSP_GETOSPACE error\n");

}

printf("bytes:%d fragments:%d fragsize:%d fragstotal:%d\n",info.bytes,info.fragments,info.fragsize,info.fragstotal);

printf("the wav sampleRate is %d\n",sampleRate);

printf("format: %d \n",format);

SigBuf = calloc(1, sizeof(short int) * frame_size);

while (read(recoder_fid, SigBuf, sizeof(short int)*frag_size))

{

fwrite(SigBuf,sizeof(short int),frag_size,fp_in);

FrameCounter++;

write(audio_fd, SigBuf, sizeof(short int)*frag_size);

}

printf("Frame number:%d \n",FrameCounter);

close(recoder_fid);

close(audio_fd);

fclose(fp_in);

free(SigBuf);

return 0;

}

程序运行图如下:

1203501226.jpg

但是从官方的文档来看,官方并不推荐这样做,http://manuals.opensound.com/developer/audio_timing.html 因为系统默认的buffer是根据你的采样率等设置自动计算的。强制设置buffer未必会达到你想要的结果,就像刚才说的,buffer的设置不能放在后面,之前我是放在后面,程序一开始运行不会出错,但是等一两分之后,程序出现了非常大的延迟,大概有两秒左右。由上面的程序运行图可以知道,OSS版本是3.08。OSS现在已经升级到4.0,所以OSS4.0也对这个时延进行了改进。http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html 可以通过以下程序设置:

int policy=The policy value;

ioctl(fd, SNDCTL_DSP_POLICY, &policy);

policy的值来设定时延的大小。Values below 5 will give lower and lower latencies with slightly increased CPU usage. Values above 5 will give lower CPU usage with increased latencies.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值