[pulseaudio-tickets] [PulseAudio] #646: writing to multiple ALSA handles in multiple threads in the same problem cause thread lockup
PulseAudio
trac-noreply at tango.0pointer.de
Mon Sep 7 01:40:50 PDT 2009
#646: writing to multiple ALSA handles in multiple threads in the same problem
cause thread lockup
----------------------+-----------------------------------------------------
Reporter: Whistler | Owner: lennart
Type: defect | Status: new
Milestone: | Component: daemon
Keywords: |
----------------------+-----------------------------------------------------
such as this code:
#define ALSA_PCM_NEW_HW_PARAMS_API
#define ALSA_PCM_NEW_SW_PARAMS_API
#include <alsa/asoundlib.h>
static snd_pcm_t *handle = NULL;
static snd_pcm_uframes_t buffer_size;
static snd_pcm_t *handle_cdda = NULL;
// SETUP CDDA SOUND
void SetupCDDASound(void)
{
snd_pcm_hw_params_t *hwparams;
unsigned int pspeed;
int pchannels = 2;
int format;
unsigned int buffer_time = 500000;
unsigned int period_time = buffer_time / 4;
int err;
pspeed = 44100;
format = SND_PCM_FORMAT_S16_LE;
if ((err = snd_pcm_open(&handle_cdda, "default",
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0)
{
printf("Audio open error: %s\n", snd_strerror(err));
return;
}
if((err = snd_pcm_nonblock(handle_cdda, 0))<0)
{
printf("Can't set blocking moded: %s\n", snd_strerror(err));
return;
}
snd_pcm_hw_params_alloca(&hwparams);
if((err=snd_pcm_hw_params_any(handle_cdda, hwparams))<0)
{
printf("Broken configuration for this PCM: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_access(handle_cdda, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED))<0)
{
printf("Access type not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_format(handle_cdda, hwparams, format))<0)
{
printf("Sample format not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_channels(handle_cdda, hwparams,
pchannels))<0)
{
printf("Channels count not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_rate_near(handle_cdda, hwparams, &pspeed,
0))<0)
{
printf("Rate not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_buffer_time_near(handle_cdda, hwparams,
&buffer_time, 0))<0)
{
printf("Buffer time error: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_period_time_near(handle_cdda, hwparams,
&period_time, 0))<0)
{
printf("Period time error: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params(handle_cdda, hwparams))<0)
{
printf("Unable to install hw params: %s\n", snd_strerror(err));
return;
}
}
// SETUP SOUND
void SetupSound(void)
{
snd_pcm_hw_params_t *hwparams;
snd_pcm_status_t *status;
unsigned int pspeed;
int pchannels;
int format;
unsigned int buffer_time = 50000;
unsigned int period_time = buffer_time / 4;
int err;
if (iDisStereo) pchannels = 1;
else pchannels=2;
pspeed = 44100;
format = SND_PCM_FORMAT_S16;
if ((err = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0)
{
printf("Audio open error: %s\n", snd_strerror(err));
return;
}
if((err = snd_pcm_nonblock(handle, 0))<0)
{
printf("Can't set blocking moded: %s\n", snd_strerror(err));
return;
}
snd_pcm_hw_params_alloca(&hwparams);
if((err=snd_pcm_hw_params_any(handle, hwparams))<0)
{
printf("Broken configuration for this PCM: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_access(handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED))<0)
{
printf("Access type not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_format(handle, hwparams, format))<0)
{
printf("Sample format not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_channels(handle, hwparams, pchannels))<0)
{
printf("Channels count not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0))<0)
{
printf("Rate not available: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_buffer_time_near(handle, hwparams,
&buffer_time, 0))<0)
{
printf("Buffer time error: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params_set_period_time_near(handle, hwparams,
&period_time, 0))<0)
{
printf("Period time error: %s\n", snd_strerror(err));
return;
}
if((err=snd_pcm_hw_params(handle, hwparams))<0)
{
printf("Unable to install hw params: %s\n", snd_strerror(err));
return;
}
snd_pcm_status_alloca(&status);
if((err=snd_pcm_status(handle, status))<0)
{
printf("Unable to get status: %s\n", snd_strerror(err));
return;
}
buffer_size = snd_pcm_status_get_avail(status);
SetupCDDASound();
}
// REMOVE SOUND
void RemoveSound(void)
{
if(handle != NULL)
{
snd_pcm_drop(handle);
snd_pcm_close(handle);
handle = NULL;
}
if(handle_cdda != NULL)
{
snd_pcm_drop(handle_cdda);
snd_pcm_close(handle_cdda);
handle_cdda = NULL;
}
}
// GET BYTES BUFFERED
unsigned long SoundGetBytesBuffered(void)
{
unsigned long l;
if (handle == NULL) // failed to open?
return SOUNDSIZE;
l = snd_pcm_avail_update(handle);
if (l < 0) return 0;
if (l < buffer_size / 2) // can we write in at
least the half of fragments?
l = SOUNDSIZE; // -> no? wait
else l = 0; // -> else go on
return l;
}
// FEED SOUND DATA
void SoundFeedStreamData(unsigned char* pSound,long lBytes)
{
if (handle == NULL) return;
if (snd_pcm_state(handle) == SND_PCM_STATE_XRUN)
snd_pcm_prepare(handle);
snd_pcm_writei(handle,pSound,
iDisStereo ? lBytes / 2 : lBytes / 4);
}
static unsigned char cdda_buf[23520];
// PLAY CDDA CHANNEL
void CALLBACK SPUplayCDDAchannel(short* pcm, int nbytes)
{
int i, size, s;
unsigned char *p = (unsigned char *)pcm;
if (handle_cdda == NULL) return;
while (nbytes > 0)
{
size = nbytes;
if (size > sizeof(cdda_buf)) size = sizeof(cdda_buf);
for (i = 0; i < size / 4; i++)
{
s = (short)(p[i*4] | (p[i*4+1] << 8));
s *= iLeftXAVol;
s /= 32767;
cdda_buf[i*4] = (s & 0xFF);
cdda_buf[i*4+1] = ((s & 0xFF00) >> 8);
s = (short)(p[i*4+2] | (p[i*4+3] << 8));
s *= iRightXAVol;
s /= 32767;
cdda_buf[i*4+2] = (s & 0xFF);
cdda_buf[i*4+3] = ((s & 0xFF00) >> 8);
}
if (snd_pcm_state(handle_cdda) == SND_PCM_STATE_XRUN)
snd_pcm_prepare(handle_cdda);
snd_pcm_writei(handle_cdda, cdda_buf, size / 4);
nbytes -= size;
p += size;
}
}
...and use SPUplayCDDAchannel() and SoundFeedStreamData() in 2 different
threads in order to mix the samples.
this works well without PulseAudio, however with the PulseAudio enabled
this will cause thread lockups from time to time.
--
Ticket URL: <http://pulseaudio.org/ticket/646>
PulseAudio <http://pulseaudio.org/>
The PulseAudio Sound Server
More information about the pulseaudio-bugs
mailing list