me wrote:

>Jaroslav Kysela wrote:
>
>>On Wed, 12 Dec 2001, Tim Goetze wrote:
>>
>>> Abramo Bagnara wrote:
>>>
>>> >Tim Goetze wrote:
>>> >>
>>> >> >>but sometimes i also get inexplicable corruption within ordinary
>>> >> >>dynamically allocated memory of the process before it exits.
>>> >> >>
>>> >> >>i have spent considerable time on verifying that these are indeed
>>> >> >>caused by changing the period_size, and not by my own code.
>>> >> >
>>> >> >i would be too certain of this conclusion. i spent many a long night
>>> >> >and day and night tracking down places in the audioengine code that
>>> >> >had overrun the mmapped areas. i was only ever to track things down by
>>> >> >generating huge log files that detailed every byte i wrote, and then
>>> >> >use perl and awk to digest them.
>>> >> >
>>> >> >i'm not saying its not a problem in ALSA, only that its unlikely at
>>> >> >this point. what have you done to ensure that its not your code? do
>>> >> >you completely avoid writing data to the mapped areas?
>>> >> >
>>> >>
>>> >> yes, exactly that. i just did
>>> >>   n * (open, configure, m * (poll, mmap_begin, mmap_commit), close)
>>> >> and nothing more.
>>> >
>>> >You're missing avail_update: it's *mandatory*.
>>> >
>>> >> i ran this twice, one time with the usual configure, and one time
>>> >> with f/c hardcoded to 64 in the hw setup so my code in all places believes
>>> >> it's going 2048, 1024, 512, ... -- not that it matters because i don't
>>> >> process any data. the one that's doing the 'real configure' crashes.
>>>
>>> yes, i did avail_update. sorry for not quoting all the 12111 lines of code
>>> involved.
>>>
>>> and before i receive another message like this: i also did snd_pcm_link,
>>> _unlink, _start and _drop.
>>
>>I think that it would be best for us to see some C code invoking the bad
>>behaviour to debug the alsa-lib's code.
>
>so thinks me too. i've isolated the audio stream code and attached it.
>
>compile with 'gcc -o a.out main.cc -lasound -L/usr/lib', and run with
>for example
>$ ./a.out hw:0,0 2048
>
>it will try to configure both streams on hw:0,0 for period_size of
>2048, 1024 ... 64. on the awe it crashes when reaching 512.
>
>this code does not even link, start, drop or unlink - just configure
>the streams. it segfaults here before exit() even if i only configured
>them one time.

just in case you find C++ repelling, i've straightened it out into 
pure C, please find it in the attachment.

no segfaulting occurs if you modify the code to setup the streams
for SND_PCM_ACCESS_RW_* instead of SND_PCM_ACCESS_MMAP_*. but i guess 
you've already found this out.

please do not interpret this as my trying to push you around -- i'm
trying to understand what is going wrong myself, but reading alsa-lib
code is not exactly an enlightening experience to a feeble mind like
mine, and i'm wondering if you have come closer to solving the problem.

tim

#include <unistd.h>
#include <stdio.h>

#include <alsa/asoundlib.h>

void
throw (char * s)
{
        fprintf (stderr, "%s\n", s);
        exit (1);
}

typedef struct
{
        snd_pcm_t * handle;
        snd_pcm_hw_params_t * hw_params;
        snd_pcm_sw_params_t * sw_params;
} AudioStream;  
        
void
AudioStream_construct (AudioStream * s)
{
        int error;
        
        s->handle = 0;
        s->hw_params = 0;
        s->sw_params = 0;

        if (snd_pcm_hw_params_malloc (&s->hw_params))
                throw ("hw_params_malloc fails.");
        if (snd_pcm_sw_params_malloc (&s->sw_params))
                throw ("sw_params_malloc fails.");
}

void
AudioStream_destruct (AudioStream * s)
{
        if (s->handle)
                snd_pcm_close (s->handle);
        
        if (s->hw_params)
                snd_pcm_hw_params_free (s->hw_params);
        if (s->sw_params)
                snd_pcm_sw_params_free (s->sw_params);
}

void
AudioStream_open (AudioStream *s, char * name, int type)
{
        if (snd_pcm_open (&s->handle, name, type, 0))
                throw ("pcm_open fails.");
}

#define CONFIGURE(what,ifnot) \
        { \
                int error = what; \
                if (error) \
                        throw (ifnot); \
        }

void
AudioStream_configure (AudioStream * s, uint sample_rate, uint frames_per_cycle)
{
        int i;
        int error;
        int interleaved;
        int bytes_per_sample;
        int channels;

        snd_pcm_format_t formats [3] = {
                SND_PCM_FORMAT_S32,
                SND_PCM_FORMAT_S16,
                SND_PCM_FORMAT_S8
        };

        CONFIGURE (snd_pcm_hw_params_any (s->handle, s->hw_params), 
                "no 'any' configuration to start with.");

        CONFIGURE (snd_pcm_hw_params_set_periods_integer (s->handle, s->hw_params),
                "no integer period size.");
        
        error = snd_pcm_hw_params_set_access 
                        (s->handle, s->hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
                        
        if (error == 0)
                interleaved = 0;
        else
        {
                CONFIGURE (snd_pcm_hw_params_set_access 
                                (s->handle, s->hw_params, 
SND_PCM_ACCESS_MMAP_INTERLEAVED),
                                "memory-mapped access method refused.");
                interleaved = 1;
        }

        /* determine sample format */
        bytes_per_sample = ~0;
        for (i = 0; i < 3; i++)
        {
                error = snd_pcm_hw_params_set_format (s->handle, s->hw_params, 
formats[i]);
                if (error == 0)
                {
                        bytes_per_sample = 4 >> i;
                        break;
                }
        }
                        
        if (bytes_per_sample > 4)
                throw ("none of (32, 16, 8) bit sample sizes available.");

        CONFIGURE (snd_pcm_hw_params_set_rate (s->handle, s->hw_params, sample_rate, 
0),
                "unsupported sample rate.");

        channels = snd_pcm_hw_params_get_channels_max (s->hw_params);

                error = snd_pcm_hw_params_set_channels (s->handle, s->hw_params, 
channels);
                if (error)
                        throw ("no channels available.");

        CONFIGURE (snd_pcm_hw_params_set_period_size 
                (s->handle, s->hw_params, (uint) frames_per_cycle, 0), /* XXX */
                "hardware refuses this frames_per_cycle setting.");

        CONFIGURE (snd_pcm_hw_params_set_periods
                (s->handle, s->hw_params, 2, 0),
                "hardware refuses 2 cycles per buffer.");

        CONFIGURE (snd_pcm_hw_params_set_buffer_size 
                (s->handle, s->hw_params, 2 * frames_per_cycle), /* XXX */
                "hardware refuses a buffer size of 2 * frames_per_cycle.");

        CONFIGURE (snd_pcm_hw_params (s->handle, s->hw_params),
                "hardware setup failed.");

        /* sw params */
        snd_pcm_sw_params_current (s->handle, s->sw_params);
        
        CONFIGURE (snd_pcm_sw_params_set_start_threshold (s->handle, s->sw_params, 
~0u),
                "cannot turn off start threshold.");
                
        CONFIGURE (snd_pcm_sw_params_set_stop_threshold (s->handle, s->sw_params, 
~0u),
                "cannot turn off stop threshold.");

        CONFIGURE (snd_pcm_sw_params_set_silence_threshold (s->handle, s->sw_params, 
0),
                "cannot set 0 silence threshold.");

        CONFIGURE (snd_pcm_sw_params_set_silence_size (s->handle, s->sw_params, 0),
                "cannot set 0 silence size.");

        CONFIGURE (snd_pcm_sw_params_set_avail_min (s->handle, s->sw_params, 
frames_per_cycle),
                "software setup for minimum available frames failed.");

        CONFIGURE (snd_pcm_sw_params (s->handle, s->sw_params),
                "software setup failed.");

        fprintf (stderr, "configured for %d %dbit %d %s.\n",
                        sample_rate, 8 << bytes_per_sample, frames_per_cycle,
                        interleaved ? "interleaved" : "linear");
}

int main (int argc, char ** argv)
{
        int fpc;

        if (argc != 3)
                throw ("give me <alsa-pcm-device-name> <initial period_size>.");
        
        if (sscanf (argv[2], "%d", &fpc) != 1) 
                throw ("initial period_size does not seem to be a number.");

        while (fpc >= 64)
        {
                AudioStream capture, playback;

                AudioStream_construct (&capture);
                AudioStream_construct (&playback);

                AudioStream_open (&capture, argv[1], SND_PCM_STREAM_CAPTURE);
                AudioStream_open (&playback, argv[1], SND_PCM_STREAM_PLAYBACK);

                AudioStream_configure (&capture, 44100, fpc);
                AudioStream_configure (&playback, 44100, fpc);

                sleep (1);

                AudioStream_destruct (&capture);
                AudioStream_destruct (&playback);

                fpc >>= 1;
        }
        return 0;
}

Reply via email to