[pulseaudio-tickets] [PulseAudio] #646: writing to multiple ALSA handles in multiple threads in the same program cause thread lockup (was: 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 03:19:11 PDT 2009
#646: writing to multiple ALSA handles in multiple threads in the same program
cause thread lockup
-----------------------+----------------------------------------------------
Reporter: Whistler | Owner: lennart
Type: defect | Status: new
Milestone: | Component: daemon
Resolution: | Keywords:
-----------------------+----------------------------------------------------
Old description:
> 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.
New description:
Such as the code in the first comment below 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.
--
Comment(by coling):
Fix up the formatting issues :) I wont comment on the problem itself, but
I'll guess that the original API is not thread safe and only works out of
luck rather than by design (just a guess tho')
--
Ticket URL: <http://pulseaudio.org/ticket/646#comment:3>
PulseAudio <http://pulseaudio.org/>
The PulseAudio Sound Server
More information about the pulseaudio-bugs
mailing list