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;
}