I'm working on the audio code for a language called Unicon and am having some trouble getting the linux code to work properly with threading and playing more than one sound at a time. We are using openAL and OggVorbis for now with some support for MP3 through libSMPEG. I can get the code to work with one sound at a time, however, when I try to play multiple sounds at the same time I get spurrious errors.
I tried to debug it with valgrind and electric fence and all I can get is a smoking gun comming from a call to alGetSourceiv(), though I don't call it in my code. I am using a struct to hold the sources and some of the information related to the OggVorb. Below is my code. Any help would be much appreciated
/* Struct to hold sources as well as ogg info and buffers */
struct sSources
{
ALuint source;
int inUse;
ALuint buffer[4];
struct OggVorbis_File oggStream;
ALenum format;
struct vorbis_info *vorbisInfo;
};
/* Sets up array of structs for a set number of sources */
struct sSources arraySource[16];
int isPlaying = -1;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* Using this to make sure I'm not using a buffer or source already in use */
int GetIndex()
{
int i;
for(i = 0; i < 16; ++i)
if(arraySource[i].inUse == 0)
{
arraySource[i].inUse += 1;
pthread_mutex_unlock(&mutex);
return i;
}
return -1;
}
...
/* Size of buffers */
#define DATABUFSIZE (4096 * 8)
/* Reads in the data to the buffers */
int OggStreamBuf(ALuint buffer, int index)
{
char pcm[DATABUFSIZE];
int size;
int section;
int result;
int active;
size = 0;
while(size < DATABUFSIZE)
{
result = ov_read(&arraySource[index].oggStream, pcm + size,
DATABUFSIZE - size, 0, 2, 1,
§ion);
if(result > 0)
size += result;
else
if(result < 0)
{
printf("bad juju\n"); fflush(stdout);
return -1;
}/* TODO: throw actual error and handle */
else
break;
}
if(size == 0)
active = 1;
else
active = 0;
alBufferData(buffer, arraySource[index].format, pcm, size,
arraySource[index].vorbisInfo->rate);
return active;
}
/* Checks to see if the buffers need to be rebuffered */
int OggPlayback(int index)
{
ALenum state;
alGetSourcei(arraySource[index].source, AL_SOURCE_STATE, &state);
if(state == AL_PLAYING)
return 0;
if(OggStreamBuf(arraySource[index].buffer[0], index) == 1)
return 1;
if(OggStreamBuf(arraySource[index].buffer[1], index) == 1)
return 1;
if(OggStreamBuf(arraySource[index].buffer[2], index) == 1)
return 1;
if(OggStreamBuf(arraySource[index].buffer[3], index) == 1)
return 1;
alSourceQueueBuffers(arraySource[index].source, 4, arraySource[index].buffer);
alSourcePlay(arraySource[index].source);
return 0;
}
/* Checks if the buffers have been processed and need to be rebuffered */
int OggUpdate(int index)
{
int processed;
int active = 0;
alGetSourcei(arraySource[index].source, AL_BUFFERS_PROCESSED,
&processed);
while(processed--)
{
ALuint buffer;
alSourceUnqueueBuffers(arraySource[index].source, 1, &buffer);
active = OggStreamBuf(buffer, index);
alSourceQueueBuffers(arraySource[index].source, 1, &buffer);
}
return active;
}
/* Cleans things up on an exit */
void OggExit(int index)
{
pthread_mutex_lock(&mutex);
isPlaying -= 1;
alSourceStop(arraySource[index].source);
alDeleteSources(1, &arraySource[index].source);
alDeleteBuffers(4, arraySource[index].buffer);
ov_clear(&arraySource[index].oggStream);
arraySource[index].inUse -= 1;
if(isPlaying == 0)
{
alutExit();
}
pthread_mutex_unlock(&mutex);
}
/* Threaded function to handle .ogg files */
void * OpenAL_PlayOgg( void * args )
{
int index;
pthread_mutex_lock(&mutex);
index = GetIndex();
pthread_mutex_unlock(&mutex);
if((ov_fopen((char *) args, &arraySource[index].oggStream) < 0))
{
pthread_mutex_lock(&mutex);
isPlaying -= 1;
arraySource[index].inUse -= 1;
if(isPlaying == 0)
alutExit();
pthread_mutex_unlock(&mutex);
return NULL;
}
arraySource[index].vorbisInfo = ov_info(&arraySource[index].oggStream, -1);
if(arraySource[index].vorbisInfo->channels == 1)
arraySource[index].format = AL_FORMAT_MONO16;
else
arraySource[index].format = AL_FORMAT_STEREO16;
alGenSources(1, &arraySource[index].source);
alGenBuffers(4, arraySource[index].buffer);
alSource3f(arraySource[index].source, AL_POSITION, 0.0, 0.0, 0.0);
alSource3f(arraySource[index].source, AL_VELOCITY, 0.0, 0.0, 0.0);
alSource3f(arraySource[index].source, AL_DIRECTION, 0.0, 0.0, 0.0);
alSourcef(arraySource[index].source, AL_ROLLOFF_FACTOR, 0.0);
alSourcei(arraySource[index].source, AL_SOURCE_RELATIVE, AL_TRUE);
/* Set up buffers and sources... not 100% sure about calling Gen and Destroy
* on the sources... */
if (OggPlayback(index) == 1)
{
OggExit(index);
return NULL;
}
while(OggUpdate(index) == 0)
{
if(OggPlayback(index) == 1)
{
OggExit(index);
return NULL;
}
}
OggExit(index);
return NULL;
}
...
/* starts here*/
void StartAudioThread(char filename[])
{
int i;
char *sp;
pthread_t AudioThread;
pthread_mutex_lock(&mutex);
if (isPlaying == -1) /* initialzation */
{
for(i = 0; i < 16; ++i)
arraySource[i].inUse = 0;
isPlaying = 0;
}
if (isPlaying == 0) /* sets up openAL if nothing is already playing */
alutInit(NULL, NULL);
isPlaying += 1;
pthread_mutex_unlock(&mutex);
if((sp = strstr(filename,".ogg")) != NULL){
#if defined(HAVE_LIBOGG)
#ifndef WIN32
if ( pthread_create( &AudioThread, NULL, OpenAL_PlayOgg , filename) ) {
return;
}
return;
...











