二、OSS开发之ioctl设置

一、声卡缓冲区设置

开发工作中,有时候可能会遇到声卡的XRUN现象,原因就是声卡缓冲区不足或满溢。

在设置OSS声卡驱动内部缓冲区时,为了防止音频抖动,保证播放性能,设置了内部缓冲区,即DMA buffer。
播放时候,首先应用程序通过驱动程序首先将音频数据从应用程序缓冲区,即APP buffer,写入到DMA buffer;接着,由DMA控制器把DMA buffer中的音频数据发送到DAC进行下一步处理

因此,可能会出现矛盾现场:

 1. 某些时刻CPU没有时间向DMA buffer放入新的音频数据,DAC由于没有输入新的音频数据,
 	导致声音播放的间断,这就出现了声音的抖动现象
 2. 如果将DMA buffer设置的足够大,使得DAC始终有数据播放,也会使得每次从APP buffer拷贝的时间也变长,
 	导致了更大的播放延迟

对于这个矛盾,可以从两个不同的方面分别着手解决

1.1 方法一

驱动程序采用多缓冲方式,即将大的DMA buffer分割成多个小的缓冲区,称之为fragment,它们的大小相同。驱动程序开始时只需等待一个fragment满了就开始播放,这样可以通过增加fragment的个数来增加缓冲区的大小,但同时每个fragment被限制在合适的大小,也不影响时延

1.2 方法二

应用程序将驱动程序中的缓冲通过mmap映射到自己地址空间后,以自己的方式来处理这些缓冲区,根据需要设置驱动程序中内部缓冲区的大小
在OSS的ioctl接口中,SNDCTL_DSP_SETFRAGMENT就是用来设置驱动程序内部缓冲区大小。具体的用法如下:

  int param;
  param = ( 0x0004 << 16) + 0x000a;
  if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, ¶m) == -1) 
  {
    
     
		printf("错误处理\n");
  }

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

一个 fragment 的播放时延 = fragment大小 / (频率 * 2 * 2)
以fragment大小为512字节为例,T = 512 / (48000 * 2 * 2)= 2.90ms
其中,480100表示48KHz的采样频率,第一个2表示双声道,第二个2表示采样深度是16bit,为2个字节

如下,也可以谈过下列方式获取当前已经设置的声卡相关信息

扫描二维码关注公众号,回复: 14976178 查看本文章
audio_buf_info audio_info;
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &audio_info) == -1)
	printf("SNDCTL_DSP_GETOSPACE error!\n");
else
	printf("bytes = %d, fragments = %d, fragsize = %d, fragstotal = %d\n", 
		audio_info.bytes, audio_info.fragments, audio_info.fragsize, audio_info.fragstotal);

二、其它设置

2.1 设置声道数目

int channels = 0;       // 0=mono 1=stereo
int result = ioctl(handle, SNDCTL_DSP_STEREO, &channels);
if(result == -1) 
{
    
    
	printf("ioctl channel number\n");
}
if(channels != 0)
{
    
    
	printf("只支持立体声\n");
}

2.2 设置声卡的采样格式

int format = 16;
int result = ioctl(handle, SNDCTL_DSP_SETFMT, &format);
if ( result == -1 ) 
{
    
    
	printf("ioctl sample format\n");
}

2.3 设置声卡的采样频率

int rate = 48000;
int result = ioctl(handle, SNDCTL_DSP_SPEED, &rate);
if ( result == -1 ) 
{
    
    
	printf("ioctl sample format\n");
}

猜你喜欢

转载自blog.csdn.net/future_sky_word/article/details/126414138
oss