[alsa-devel] ALSA throwing buffers away?
Hello, I am developing driver for a really simple hardware. Hardware has codec that supports mono/stereo and the amplifier that supports only one speaker so the driver has to be mono driver and the codec is setup to manage mono data. I have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U8, .channels_min = 1, .channels_max = 1,
Initially I was happy since sound started playing right away, but I noticed that songs are skipping. I created buffers that collect statistics about playback which is printed at the STOP trigger. The hardware is going through ALSA circular buffer correctly, and ALSA is filling the buffer as the hardware progresses, but after each buffer iteration ALSA skips the buffer length of the data?! For example: If buffer is .5 Mb ALSA will fill first .5Mb from the file into the buffer. As the hardware is playing the sound ALSA fills the buffer starting 1.0 Mb away from the begining of the file (the data from .5-1.0 Mb never makes it to the buffer). This pattern repeats constantly to the end of the song. I have tried SNDRV_PCM_INFO_INTERLEAVED with the same results (in this case ALSA will not even try to play stereo files using my mono driver). The files I tested are stereo and mono and they all behave the same. I am collecting ALSA info in the snd_pcm_lib_write1 method in the pcm_lib.c file. I was wondering if ALSA maybe deals with two circular buffers in the same time, or if anybody has an idea what is going on here?
~cheers, Ogi
Radivoje Jovanovic wrote:
I am developing driver for a really simple hardware. Hardware has codec that supports mono/stereo and the amplifier that supports only one speaker so the driver has to be mono driver and the codec is setup to manage mono data. I have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED |
Better use SNDRV_PCM_INFO_INTERLEAVED; this is the format used by almost all (stereo) sound cards, and so it is expected even for mono files (where there actually isn't any difference).
after each buffer iteration ALSA skips the buffer length of the data?!
This might be a problem with the reporting of the DMA pointer.
Please explain (or show) how your DMA works and how the pointer callback is implemented.
I have tried SNDRV_PCM_INFO_INTERLEAVED with the same results (in this case ALSA will not even try to play stereo files using my mono driver).
When using the "default" or "plughw" device, alsa-lib will automatically convert the sample format.
Regards, Clemens
Radivoje Jovanovic wrote:
I am developing driver for a really simple hardware. Hardware has codec
that
supports mono/stereo and the amplifier that supports only one speaker so
the
driver has to be mono driver and the codec is setup to manage mono data.
I
have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED |
Better use SNDRV_PCM_INFO_INTERLEAVED; this is the format used by almost all (stereo) sound cards, and so it is expected even for mono files (where there actually isn't any difference).
I am worried about this approach since if I want to play stereo sound I would have to increase .channels_max = 2, since if I keep it to 1 ALSA will report that hw configuration does not match and it will not play stereo at all. If I increase .channels_max=2 am I going to get only L or R channel for my mono therefore I will be throwing one channel away?
after each buffer iteration ALSA skips the buffer length of the data?!
This might be a problem with the reporting of the DMA pointer.
Please explain (or show) how your DMA works and how the pointer callback is implemented.
Here is my pointer callback:
offset=READ_REG16(AUDIO_ CONFIG_DMA_CUR_ADDR_HIGH))<<16) | READ_REG16(AUDIO_CONFIG_DMA_CUR_ADDR_LOW);
offset = offset - substream->runtime->dma_addr;
if (offset >= runtime->buffer_size) offset = 0; return offset;
I am also collecting the data in each interrupt routine from the hardware:
trip:9dc04000 next_trip:9dc08000 current_DMA_Location:9dc04000 ALSA reports from snd_pcm_lib_write1 that is filling the buffer from 0-16384. The first byte of the data ALSA fills is buffer away from where it should be which is wrong.
trip:9dc08000 next_trip:9dc0c000 current_DMA_Location:9dc08000 ALSA reports from snd_pcm_lib_write1 that is filling the buffer from 16384 - 2*16384. The first byte of the data is exactly 16384 away from the first byte of previous fill which is 100% correct.
trip:9dc0c000 next_trip:9dc10000 current_DMA_Location:9dc0c000 ALSA reports from snd_pcm_lib_write1 that is filling the buffer from 2*16384 - 3*16384. The first byte of the data is exactly 16384 away from the first byte of previous fill which is 100% correct.
trip:9dc10000 next_trip:9dc14000 current_DMA_Location:9dc10000 ALSA reports that is filling the buffer from 3*16384 - 4*16384. The first byte of the data is exactly 16384 away from the first byte of previous fill which is 100% correct.
trip:9dc14000 next_trip:9dc18000 current_DMA_Location:9dc14000 ALSA reports from snd_pcm_lib_write1 that is filling the buffer from 4*16384 - 5*16384. The first byte of the data is exactly 16384 away from the first byte of previous fill which is 100% correct.
and this continues to the end of the buffer like this. The buffer size is 524288, period size is 16384 and the interrupts are generated every period size. All of the info has the jiffies time stamp as well. Out of here I can see that the hardware is following the buffer correctly and that ALSA is correctly filling the buffer, but with wrong data.
~cheers, Ogi
On Tue, Nov 23, 2010 at 9:03 AM, Clemens Ladisch clemens@ladisch.de wrote:
Radivoje Jovanovic wrote:
I am developing driver for a really simple hardware. Hardware has codec
that
supports mono/stereo and the amplifier that supports only one speaker so
the
driver has to be mono driver and the codec is setup to manage mono data.
I
have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED |
Better use SNDRV_PCM_INFO_INTERLEAVED; this is the format used by almost all (stereo) sound cards, and so it is expected even for mono files (where there actually isn't any difference).
after each buffer iteration ALSA skips the buffer length of the data?!
This might be a problem with the reporting of the DMA pointer.
Please explain (or show) how your DMA works and how the pointer callback is implemented.
I have tried SNDRV_PCM_INFO_INTERLEAVED with the same results (in this case ALSA will not even try to play stereo files using my mono driver).
When using the "default" or "plughw" device, alsa-lib will automatically convert the sample format.
Regards, Clemens
Radivoje Jovanovic wrote:
Radivoje Jovanovic wrote:
I am developing driver for a really simple hardware. Hardware has codec that supports mono/stereo and the amplifier that supports only one speaker so the driver has to be mono driver and the codec is setup to manage mono data. I have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED |
Better use SNDRV_PCM_INFO_INTERLEAVED; this is the format used by almost all (stereo) sound cards, and so it is expected even for mono files (where there actually isn't any difference).
I am worried about this approach since if I want to play stereo sound I would have to increase .channels_max = 2,
No, ALSA can automatically convert the sample format.
Here is my pointer callback:
offset=READ_REG16(AUDIO_CONFIG_DMA_CUR_ADDR_HIGH))<<16) | READ_REG16(AUDIO_CONFIG_DMA_CUR_ADDR_LOW);
offset = offset - substream->runtime->dma_addr;
This offset looks as if it is in bytes, but you have to return a value measured in frames. Use bytes_to_frames().
if (offset >= runtime->buffer_size) offset = 0;
Remove this check; the ALSA framework already checks this and outputs debugging info if this happens.
Regards, Clemens
I have changed the pointer callback as you suggest. Unfortunately, the result is still the same. Still the buffer filling is skipping to fill all the data correctly. I am using Advanced Linux Sound Architecture Driver Version 1.0.21. ~cheers, Ogi
On Tue, Nov 23, 2010 at 9:40 AM, Clemens Ladisch clemens@ladisch.de wrote:
Radivoje Jovanovic wrote:
Radivoje Jovanovic wrote:
I am developing driver for a really simple hardware. Hardware has
codec that
supports mono/stereo and the amplifier that supports only one speaker
so the
driver has to be mono driver and the codec is setup to manage mono
data. I
have setup ALSA with following parameters:
.info = (SNDRV_PCM_INFO_NONINTERLEAVED |
Better use SNDRV_PCM_INFO_INTERLEAVED; this is the format used by
almost
all (stereo) sound cards, and so it is expected even for mono files (where there actually isn't any difference).
I am worried about this approach since if I want to play stereo sound I would have to increase .channels_max = 2,
No, ALSA can automatically convert the sample format.
Here is my pointer callback:
offset=READ_REG16(AUDIO_CONFIG_DMA_CUR_ADDR_HIGH))<<16) |
READ_REG16(AUDIO_CONFIG_DMA_CUR_ADDR_LOW);
offset = offset - substream->runtime->dma_addr;
This offset looks as if it is in bytes, but you have to return a value measured in frames. Use bytes_to_frames().
if (offset >= runtime->buffer_size) offset = 0;
Remove this check; the ALSA framework already checks this and outputs debugging info if this happens.
Regards, Clemens
participants (2)
-
Clemens Ladisch
-
Radivoje Jovanovic