[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Linrad] Linrad-02.46 and ALSA

Hi All,

The below is only for Linux users who want to use native ALSA.
Windows OSS and alsa-oss are not affected.


Today I received this bug report from Ermanno.
> This afternoon I'm trying Linrad-46a.
> I get the error [1300] open_rx_sndin: Invalid period size.
> In particular when I change the size of fft2.
> Not happening with vers. 045b.

The reason is that Linrad02-46 is more flexible in how it
sets the block size for reading and writing to sound cards.
The changes are motivated by a desire to run REALLY long
transforms that may span one minute in time. Under such
circumstances, the longest possible block size is desired
for the soundcards........

Linrad finds out how much time delay there is from antenna to
loudspeaker and selects buffer sizes that will not add too much
to the total delay. Since the device drivers are told to
use the same buffer size as its DMA block size this will set
how often the hardware has to answer to interrupts. With
extreme parameters the DMA rate could go very high and therefore
a parameter in the general setup (par_userint) was added some time
ago to allow the user to set an upper limit to not load his
computer with too much overhead.

The upper end of the DMA rate is probably ok with all systems, but
as it turns out when I check the reason for Ermannos observation
the low end is NOT ok under native ALSA. With delta44 running
at 96kHz and with high resolution in the second fft, Linrad could
select to read 8192 samples in each block. That means that the
interrupt rate would be 11.35 Hz (with an extra delay of 0.1 
seconds.) As it turns out, 8192*16=131072 bytes is a too big buffer
for ALSA. To correct the problem, change lsetad.c as indicated 
here (near line 1075):
// Set period size:
// We want the period_size to match ad_read_fragments
val = ad_read_fragments;
if ((err =snd_pcm_hw_params_set_period_size(ad_handle,hw_ad_params, val, 0)<0))
  if(val > 256)goto periodset;
  rx_audio_in = -1;
This will set the largest possible value. Linrad will continue to read
the same block size, but it will read several DMA blocks each time. 
(It does not matter because Linrad uses a separate thread for read that
will return when the specified number of bytes have arrived and the
fft thread can not use smaller chunks of data than a complete transform 

The output side is problematic under native ALSA however. I have not
been able to find out what buffer size to set.

The function snd_pcm_writei(da_handle, rx_da_wrbuf,da_frames) returns
the error "short write" if da_frames is set to a large value. This does not
make sense because Linrad assumes that the output device will stay
in the function until all data has flooded out. (Blocking writes are used
under OSS.)

To avoid the error "[1146]lir_rx_dawrite/writei: short write." one has 
to maximise rx_daout_block like this:

//******************** SET PLAYBACK PARAMETERS THE ALSA WAY ******
    if(rx_daout_block > 256)rx_daout_block=256;
    while(rx_output_blockrate > ui.max_dma_rate && rx_daout_block < 256)
    if ((err = snd_pcm_hw_params_malloc (&hw_da_params)) < 0)

This is however not the proper solution since a small block size means 
that the thread responsible for sending data to the output thread will
have to awake frequently which might be a problem when long transforms
are computed on a machine with only one core of modest speed.

I have not been able to find man pages for ALSA and finding any
usable information at the alsa-projet site way beyond my abilities

The above fix should work as a temporary solution. Hopefully.

73  Leif / SM5BSZ

You received this message because you are subscribed to the Google Groups "Linrad" group.
To post to this group, send email to linrad@xxxxxxxxxxxxxxxx
To unsubscribe from this group, send email to linrad-unsubscribe@xxxxxxxxxxxxxxxx
For more options, visit this group at http://groups.google.com/group/linrad?hl=en