[alsa-devel] XRUN happens too often.
I use "default" pcm and open it in block mode. Then, I set the this pcm to perform 16-bit, two channels, and 44100 bps sampling rate audio data. The number of periods per buffer is 10.
The follows are the parameters that I read from the pcm. sampling rate = 44100 bps period time = 21333 us period size = 940 frames buffer time = 213330 us buffer size = 9408 frames
A sample in 16-bit, two channels is 4 bytes. I allocate a audio data of 9408x4=37632 bytes.
audio_data=malloc(buffer_size*4);
This audio_data buffer will receive audio data from the network. If this buffer is full, I use snd_pcm_writei( ) to put the buffer into the pcm.
snd_pcm_sframes_t frames; snd_pcm_t *handle;
while((frame=snd_pcm_writei(handle, audio_data, buffer_size))<0) { if(frames==-EPIPE) snd_pcm_prepare(handle); else printf("snd_pcm_writei error %d\n", frames); }
The codes states that I put the entire buffer into the pcm at each time. The pcm use 10 periods to perform this buffer. The program can work normally.
If the sampling rate is changed, the program will encounter XRUN frequently.
The follows are the parameters that I read from the pcm after setting sampling rate to 48000. sampling rate = 48000 bps period time = 21333 us period size = 1024 frames buffer time = 213330 us buffer size = 10240 frames audio_data=malloc(buffer_size*4); //10240x4=40960
I also put the entire buffer into the pcm at each time, but snd_pcm_writei( ) will return -PIPE frequently.
What is the problem?
A sample in 16-bit, two channels is 4 bytes. I allocate a audio data of 9408x4=37632 bytes.
audio_data=malloc(buffer_size*4);
This audio_data buffer will receive audio data from the network. If this buffer is full, I use snd_pcm_writei( ) to put the buffer into the
pcm.
snd_pcm_sframes_t frames; snd_pcm_t *handle;
while((frame=snd_pcm_writei(handle, audio_data, buffer_size))<0) { if(frames==-EPIPE) snd_pcm_prepare(handle); else printf("snd_pcm_writei error %d\n", frames); }
The codes states that I put the entire buffer into the pcm at each time. The pcm use 10 periods to perform this buffer. The program can work normally.
If the sampling rate is changed, the program will encounter XRUN frequently.
The follows are the parameters that I read from the pcm after setting
sampling
rate to 48000. sampling rate = 48000 bps period time = 21333 us period size = 1024 frames buffer time = 213330 us buffer size = 10240 frames audio_data=malloc(buffer_size*4); //10240x4=40960
I also put the entire buffer into the pcm at each time, but snd_pcm_writei( ) will return -PIPE frequently.
What is the problem?
---------------------------------------------------------- I use snd_pcm_avail_update( ) to show the number of frames that can write into the pcm before using snd_pcm_writei( ). I found that sometimes snd_pcm_avail_update( ) will return more than buffer size. EX. buffer size = 10240, sometimes snd_pcm_avail_update( ) 10274 > 10240. Dose this cause XRUN? How to improve it ?
Rong-Jhe wrote:
A sample in 16-bit, two channels is 4 bytes. I allocate a audio data of 9408x4=37632 bytes.
audio_data=malloc(buffer_size*4);
This audio_data buffer will receive audio data from the network. If this buffer is full, I use snd_pcm_writei( ) to put the buffer into the
pcm.
snd_pcm_sframes_t frames; snd_pcm_t *handle;
while((frame=snd_pcm_writei(handle, audio_data, buffer_size))<0) { if(frames==-EPIPE) snd_pcm_prepare(handle); else printf("snd_pcm_writei error %d\n", frames); }
The codes states that I put the entire buffer into the pcm at each time. The pcm use 10 periods to perform this buffer. The program can work normally.
If the sampling rate is changed, the program will encounter XRUN frequently.
The follows are the parameters that I read from the pcm after setting
sampling
rate to 48000. sampling rate = 48000 bps period time = 21333 us period size = 1024 frames buffer time = 213330 us buffer size = 10240 frames audio_data=malloc(buffer_size*4); //10240x4=40960
I also put the entire buffer into the pcm at each time, but snd_pcm_writei( ) will return -PIPE frequently.
What is the problem?
I use snd_pcm_avail_update( ) to show the number of frames that can write into the pcm before using snd_pcm_writei( ). I found that sometimes snd_pcm_avail_update( ) will return more than buffer size. EX. buffer size = 10240, sometimes snd_pcm_avail_update( ) 10274 > 10240. Dose this cause XRUN? How to improve it ?
I don't have a direct answer for you, but I have an application that seems to be able to write data using writei with no problems at rates up to 192 KHz. You can download it from sourceforge and look at the source.
http://sourceforge.net/projects/discord/
I copied and adapted from other examples on the web. Do a search for alsa in the source code and it should take you to the initialization function and the playing function.
I don't have a direct answer for you, but I have an application that seems to be able to write data using writei with no problems at rates up to 192 KHz. You can download it from sourceforge and look at the source.
http://sourceforge.net/projects/discord/
I copied and adapted from other examples on the web. Do a search for alsa in the source code and it should take you to the initialization function and the playing function.
Thanks for your help. I think that XRUN may happen because the time of using snd_pcm_writei(). I have a problem about snd_pcm_write(). If the pcm is block, when does snd_pcm_writei() return?
I try to write the audio data into the dsp file directly without ALSA library. The data will be written into DMA of the soundcard. This action of writting is asynchronous, and the write() returns after queueing the data intto the DMA.
I guess the problem may be caused by the late time which the second snd_pcm_writei() is called. The time between two snd_pcm_writei() may be too long, so the pcm enters XRUN state.
The period time in this pcm is 21333 us, and the buffer time is 213330 us because there are 10 periods in a buffer.
I recorded the time timeA that snd_pcm_writei() is called, and the time timeB that snd_pcm_writei() returns. I calculate the duration between timeA and timeB, and the duration is not regular.
If snd_pcm_writei() is synchronous, the duration may be equal to the buffer time( 10xperiod time). According to the measurement, snd_pcm_writei() seems not to be synchronous. Can anyone tell me the basic theory of snd_pcm_writei(), especially in dmix mode.
Rong-Jhe wrote:
I don't have a direct answer for you, but I have an application that seems to be able to write data using writei with no problems at rates up to 192 KHz. You can download it from sourceforge and look at the source.
http://sourceforge.net/projects/discord/
I copied and adapted from other examples on the web. Do a search for alsa in the source code and it should take you to the initialization function and the playing function.
Thanks for your help. I think that XRUN may happen because the time of using snd_pcm_writei(). I have a problem about snd_pcm_write(). If the pcm is block, when does snd_pcm_writei() return?
I try to write the audio data into the dsp file directly without ALSA library. The data will be written into DMA of the soundcard. This action of writting is asynchronous, and the write() returns after queueing the data intto the DMA.
I guess the problem may be caused by the late time which the second snd_pcm_writei() is called. The time between two snd_pcm_writei() may be too long, so the pcm enters XRUN state.
The period time in this pcm is 21333 us, and the buffer time is 213330 us because there are 10 periods in a buffer.
I recorded the time timeA that snd_pcm_writei() is called, and the time timeB that snd_pcm_writei() returns. I calculate the duration between timeA and timeB, and the duration is not regular.
If snd_pcm_writei() is synchronous, the duration may be equal to the buffer time( 10xperiod time). According to the measurement, snd_pcm_writei() seems not to be synchronous. Can anyone tell me the basic theory of snd_pcm_writei(), especially in dmix mode.
I'm not sure I understand what your asking, and I don't know if I'm the right person to answer at any rate :-), but here goes.
I think you are asking why there is variation in the time that a system call takes (writei is calling the alsa library, a system library), and if so then it is because all modern OSs have multitasking and interrupts. Even hardened real time systems can have variation on interrupt call response times, depending on what is happening. The write to the sound device is an interrupt, and the OS controls that.
That being said, if you are having underruns because of interrupt processing time you are very close to the limit on your system. I don't think that can be it unless you are doing something like video processing at the time you are playing, or something like beagle or dbupdate is running (higher priority tasks than the sound card unless you have real time sound set).
On Wed, Apr 9, 2008 at 6:28 PM, stan ghjeold_i_mwee@cox.net wrote:
That being said, if you are having underruns because of interrupt processing time you are very close to the limit on your system. I don't think that can be it unless you are doing something like video processing at the time you are playing, or something like beagle or dbupdate is running (higher priority tasks than the sound card unless you have real time sound set).
Rong-Jhe,
If you aren't already, try using SCHED_FIFO priority for your audio thread.
Lee
Thanks to all that answer my question. My application is receiving audio data from newtork and play it with ALSA library. The environment is in ARM not in PC. The same codes can not perform well in ARM as in PC. I have not seen the implementation of snd_pcm_writei(), and only read the document of ALSA to use this function. I guess snd_pcm_writei() will generate a thread that can write data into the DMA of soundcard at each period. This may explain why the duration of snd_pcm_writei() is not regular, and why ALSA lib can use function call to implement mixing without a mixing server. Sometimes the duration is long and sometimes is short. This may be caused by the generation of the thread in snd_pcm_writei().
I think the thread plays the role of mixing server and terminates when all the periods of buffer are played. Then XRUN state is entered. In my environment, the speed of receiving audio data from network is slow than playing audio data with snd_pcm_writei(). In the beginning, the pcm will enter XRUN state, because the audio data from network is not full enough to play. I use more buffer to receive data and play less buffer with snd_pcm_writei(), so the time that audio buffer runs out can be delayed. The delay can let the thread in snd_pcm_writei() to have enough space to play audio data. When the buffer runs out, the thread in snd_pcm_writei() may still has remaining data to play, so XRUN won't happen.
I don't know whether I am right. After I see the implementation of snd_pcm_writei(), I may have more correct explanation.
On Wed, Apr 9, 2008 at 11:29 PM, Rong-Jhe r93922118@ntu.edu.tw wrote:
Thanks to all that answer my question. My application is receiving audio data from newtork and play it with ALSA library. The environment is in ARM not in PC. The same codes can not perform well in ARM as in PC. I have not seen the implementation of snd_pcm_writei(), and only read the document of ALSA to use this function. I guess snd_pcm_writei() will generate a thread that can write data into the DMA of soundcard at each period. This may explain why the duration of snd_pcm_writei() is not regular, and why ALSA lib can use function call to implement mixing without a mixing server.
ALSA does not generate threads for you like this. I was referring to your application's audio thread, assuming that your app is indeed multithreaded.
The duration probably varies because the call to snd_pcm_writei() will block until there is enough space in the ALSA ringbuffer to receive your data.
Lee
ALSA does not generate threads for you like this. I was referring to your application's audio thread, assuming that your app is indeed multithreaded.
The duration probably varies because the call to snd_pcm_writei() will block until there is enough space in the ALSA ringbuffer to receive your data.
Lee
I found that there will be a thread generated after calling snd_pcm_open(). I use command 'ps' to check it. Due to this I guess snd_pcm_writei() only put the data into the buffer of the thread 'pcm'.
This thread then schedules of mixes the audio data, and put it into the buffer of ALSA driver. ALSA ringbuffer only belongs to ALSA library, and ALSA driver uses anoother buffer in kernel. Thus, there must be a thread that can put the data in ALSA ringbuffer into the buffer of ALSA driver.
On Thu, 10 Apr 2008, Rong-Jhe wrote:
ALSA does not generate threads for you like this. I was referring to your application's audio thread, assuming that your app is indeed multithreaded.
The duration probably varies because the call to snd_pcm_writei() will block until there is enough space in the ALSA ringbuffer to receive your data.
Lee
I found that there will be a thread generated after calling snd_pcm_open(). I use command 'ps' to check it. Due to this I guess snd_pcm_writei() only put the data into the buffer of the thread 'pcm'.
Nope, you probably use dmix plugin. This thread is only for management for shared device and has nothing to do with sample transfers.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
Jaroslav Kysela <perex <at> perex.cz> writes:
Nope, you probably use dmix plugin. This thread is only for management for shared device and has nothing to do with sample transfers.
Jaroslav
Sorry, I am confused with the mechanism of ALSA library. I roughly viewed the implementation of snd_pcm_writei(). In my config, snd_pcm_writei() will call snd_pcm_mmap_writei(). In snd_pcm_mmap_writei(), the available space is checked, and will wait for available space if the pcm is in block mode and the space is not large enough. Then snd_pcm_mmap_write_area() is called. I think that snd_pcm_mmap_commit() do the work of put data into the buffer in user space. Function snd_pcm_mmap_commit() shoud call snd_pcm_dmix_mmap_commit in my config. I saw snd_pcm_dmix_start_timer() here, and snd_pcm_dmix_start_timer() calls ioctl(). I don't know which file in ALSA driver will receive this ioctl system call. Does this function start something like timer, and this timer will put the buffer in user space into the buffer in kernel space automatically? I can't understand this mechanism. I am confused with the interaction between ALSA library and ALSA driver. I think the mixing procedure is implemented in user space, and ALSA driver only put the mixed buffer from user space to the soundcard. Am I right?
I found that there will be a thread generated after calling snd_pcm_open(). I use command 'ps' to check it. Due to this I guess snd_pcm_writei() only put the data into the buffer of
the
thread 'pcm'.
This thread then schedules of mixes the audio data, and put it into the
buffer
of ALSA driver. ALSA ringbuffer only belongs to ALSA library, and ALSA driver uses anoother buffer in kernel. Thus, there must be a thread that can put the data in ALSA ringbuffer into
the
buffer of ALSA driver.
I found that snd_pcm_direct_server_create() in ALSA library will create a thread. This resolves my problem that why ALSA library needn't use a daemon to mixing audio like other mixing server.
Rong-Jhe wrote:
buffer size = 9408 frames
A sample in 16-bit, two channels is 4 bytes. I allocate a audio data of 9408x4=37632 bytes.
audio_data=malloc(buffer_size*4);
This audio_data buffer will receive audio data from the network. If this buffer is full, I use snd_pcm_writei( ) to put the buffer into the pcm.
When this buffer is full, the device buffer is completely empty, and even the slightest delay will result in an underrun.
Write data to the device buffer immediately when you receive it.
HTH Clemens
participants (5)
-
Clemens Ladisch
-
Jaroslav Kysela
-
Lee Revell
-
Rong-Jhe
-
stan