• 二、OSS开发之缓冲区设置


    一、声卡缓冲区设置

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

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

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

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

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

    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");
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    参数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个字节

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

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二、其它设置

    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");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.2 设置声卡的采样格式

    int format = 16;
    int result = ioctl(handle, SNDCTL_DSP_SETFMT, &format);
    if ( result == -1 ) 
    {
    	printf("ioctl sample format\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.3 设置声卡的采样频率

    int rate = 48000;
    int result = ioctl(handle, SNDCTL_DSP_SPEED, &rate);
    if ( result == -1 ) 
    {
    	printf("ioctl sample format\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    【翠花Vue之旅】vue打卡8
    Hadoop入门介绍
    Java版的数据结构——栈和队列
    ZYNQ中断例程
    有人知道这个动作模型是哪里的吗?叫什么?
    19. Remove Nth Node From End of List
    解决gradle下载慢的问题
    Python通过selenium调用IE11浏览器报错解决方法
    华为无线设备配置双链路冷备份(AP指定配置方式)
    深夜看代码2
  • 原文地址:https://blog.csdn.net/future_sky_word/article/details/126414138