2. ioctl settings for OSS development

1. Sound card buffer settings

In the development work, sometimes you may encounter the XRUN phenomenon of the sound card, the reason is that the buffer of the sound card is insufficient or full.

When setting the OSS sound card to drive the internal buffer, in order to prevent audio jitter and ensure playback performance, the internal buffer, namely DMA buffer, is set.
When playing, the application first writes the audio data from the application buffer, namely the APP buffer, to the DMA buffer through the driver; then, the DMA controller sends the audio data in the DMA buffer to the DAC for further processing

Therefore, a contradictory scene may arise:

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

For this contradiction, we can solve it from two different aspects.

1.1 Method 1

The driver adopts the multi-buffer mode, that is, the large DMA buffer is divided into multiple small buffers, which are called fragments, and their sizes are the same. At the beginning, the driver only needs to wait for a fragment to be full before starting to play, so that the size of the buffer can be increased by increasing the number of fragments, but at the same time each fragment is limited to an appropriate size, and the delay is not affected

1.2 Method 2

After the application program maps the buffer in the driver to its own address space through mmap, it processes these buffers in its own way, and sets the size of the internal buffer in the driver according to the needs. In the ioctl interface of OSS, SNDCTL_DSP_SETFRAGMENT is used to
set Driver internal buffer size. The specific usage is as follows:

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

The parameter param consists of two parts: the lower 16 bits are the size of the fragment, here 0x000a means that the size of the fragment is 2^0xa, that is, 1024 bytes; the upper 16 bits are the number of fragments, here is 0x0004, that is, 4 fragments. After setting the fragment parameters, adjust the buffer in the driver through the SNDCTL_DSP_SETFRAGMENT command of ioctl.

The playback delay of a fragment = fragment size / (frequency * 2 * 2)
Take the fragment size of 512 bytes as an example, T = 512 / (48000 * 2 * 2) = 2.90ms
where 480100 represents the sampling frequency of 48KHz, The first 2 means two channels, and the second 2 means that the sampling depth is 16bit, which is 2 bytes

As follows, you can also talk about the following ways to obtain information about the currently set sound card

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. Other settings

2.1 Set the number of channels

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 Set the sampling format of the sound card

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

2.3 Set the sampling frequency of the sound card

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

Guess you like

Origin blog.csdn.net/future_sky_word/article/details/126414138