threaded openAL audio library

20ac5dce03dc8d5387fe4b5b95222983
0
ghollingshead 101 Jul 01, 2010 at 22:13

Hello. This is my first post so I hope I don’t mess it up too bad ;).
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,
                   &section);
      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;
...

2 Replies

Please log in or register to post a reply.

5ccedf5e0f538b594eb578f003ade3eb
0
Hyper 96 Jul 03, 2010 at 16:49

@ghollingshead

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.

If you wouldn’t mind (for my own curiosity), would you mind posting the errors (as long as there isn’t \~100)? :)

20ac5dce03dc8d5387fe4b5b95222983
0
ghollingshead 101 Jul 06, 2010 at 20:35

Sure thing. I’ve also added a line to print out what index I am in and what source I’m using It is as follows:

printf("index is %i and playing %i on source %i\n", indexSource, isPlaying, (int)arraySource[indexSource].source); fflush(stdout);

I’ve done a couple tests and noted that it seems to be able to play one sound nearly continuously, though with the spurious errors it’s hard to say that for certain. Also, after an hour of testing, I couldn’t get the alGetSourceiv() to come up on gdb again. The following are gdb runs of the code:

index is 11 and playing 15 on source 16441
[Thread 0x988d5b90 (LWP 10018) exited]
index is 14 and playing 15 on source 16442
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x978d3b90 (LWP 10020)]
0xb7bfea39 in alBufferData () from /usr/lib/libopenal.so.0
(gdb) where
#0  0xb7bfea39 in alBufferData () from /usr/lib/libopenal.so.0
#1  0xb3248fe8 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

And another…:

[New Thread 0x9f610b90 (LWP 10149)]
index is 12 and playing 13 on source 16413
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xa2616b90 (LWP 10143)]
0xb7c2ba39 in alBufferData () from /usr/lib/libopenal.so.0
(gdb) where
#0  0xb7c2ba39 in alBufferData () from /usr/lib/libopenal.so.0
#1  0xb3275fe8 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

And…:

[New Thread 0x72b90b90 (LWP 10596)]
index is 3 and playing 11 on source 16502
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb200cb90 (LWP 10478)]
0xb7d0f638 in ?? () from /usr/lib/libopenal.so.0
(gdb) where
#0  0xb7d0f638 in ?? () from /usr/lib/libopenal.so.0
(gdb) info threads
  120 Thread 0x72b90b90 (LWP 10596)  0xb807c704 in memalign () from /usr/lib/libefence.so.0
  119 Thread 0x73391b90 (LWP 10595)  0xb7c4a16f in vorbis_book_decodevv_add () from /usr/lib/libvorbis.so.0
  118 Thread 0x73b92b90 (LWP 10594)  0xb7d259bc in ?? () from /usr/lib/libopenal.so.0
  117 Thread 0x74393b90 (LWP 10593)  0xb7b079a0 in ?? () from /lib/libc.so.6
  116 Thread 0x74b94b90 (LWP 10592)  0xb7b079a0 in ?? () from /lib/libc.so.6
  115 Thread 0x75395b90 (LWP 10591)  0xb7d1396a in ?? () from /usr/lib/libopenal.so.0
  114 Thread 0x75b96b90 (LWP 10590)  0xb7b079a0 in ?? () from /lib/libc.so.6
  113 Thread 0x76397b90 (LWP 10589)  0xb7d12286 in alGetSourceiv () from /usr/lib/libopenal.so.0
  112 Thread 0x76b98b90 (LWP 10588)  0xb7d1397a in ?? () from /usr/lib/libopenal.so.0
  111 Thread 0x77399b90 (LWP 10587)  0xffffe430 in __kernel_vsyscall ()
  110 Thread 0x77b9ab90 (LWP 10586)  0xb7d13940 in ?? () from /usr/lib/libopenal.so.0
  109 Thread 0x7839bb90 (LWP 10585)  0xffffe430 in __kernel_vsyscall ()
* 2 Thread 0xb200cb90 (LWP 10478)  0xb7d0f638 in ?? () from /usr/lib/libopenal.so.0
  1 Thread 0xb6aea6f0 (LWP 10475)  0xffffe430 in __kernel_vsyscall ()
warning: Couldn't restore frame in current thread, at frame 0
0xb7d0f638 in ?? () from /usr/lib/libopenal.so.0

Finally…:

[New Thread 0x1c9adb90 (LWP 11585)]
index is 9 and playing 15 on source 16673
index is 4 and playing 15 on source 16674
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb1fd4b90 (LWP 11289)]
0xb7cddbd0 in ?? () from /usr/lib/libopenal.so.0
(gdb) where
#0  0xb7cddbd0 in ?? () from /usr/lib/libopenal.so.0
#1  0xd761d761 in ?? ()
Cannot access memory at address 0xdb8adb8e
(gdb) info threads
  292 Thread 0x1c9adb90 (LWP 11585)  0xb7c13930 in vorbis_book_init_decode () from /usr/lib/libvorbis.so.0
  291 Thread 0x1d1aeb90 (LWP 11584)  0xffffe430 in __kernel_vsyscall ()
  290 Thread 0x1d9afb90 (LWP 11583)  0xffffe430 in __kernel_vsyscall ()
  289 Thread 0x1e6b0b90 (LWP 11582)  0xb7cdb940 in ?? () from /usr/lib/libopenal.so.0
  288 Thread 0x1eeb1b90 (LWP 11581)  0xb7cda16d in alGetSourceiv () from /usr/lib/libopenal.so.0
  287 Thread 0x1f7b2b90 (LWP 11580)  0xffffe430 in __kernel_vsyscall ()
  286 Thread 0x1ffb3b90 (LWP 11579)  0xb7cdb934 in ?? () from /usr/lib/libopenal.so.0
  285 Thread 0x207b4b90 (LWP 11578)  0xb7cdb97a in ?? () from /usr/lib/libopenal.so.0
  284 Thread 0x210b5b90 (LWP 11577)  0xb7ced983 in ?? () from /usr/lib/libopenal.so.0
  283 Thread 0x218b6b90 (LWP 11576)  0xb7cda860 in alGetSourcei () from /usr/lib/libopenal.so.0
  282 Thread 0x220b7b90 (LWP 11575)  0x080fd90a in OggUpdate (index=11) at raudio.r:599
  281 Thread 0x228b8b90 (LWP 11574)  0xb7ced983 in ?? () from /usr/lib/libopenal.so.0
  280 Thread 0x230b9b90 (LWP 11573)  0xb7cda10f in alGetSourceiv () from /usr/lib/libopenal.so.0
  279 Thread 0x238bab90 (LWP 11572)  0xffffe430 in __kernel_vsyscall ()
  278 Thread 0x240bbb90 (LWP 11571)  0xb8044469 in free () from /usr/lib/libefence.so.0
* 2 Thread 0xb1fd4b90 (LWP 11289)  0xb7cddbd0 in ?? () from /usr/lib/libopenal.so.0
  1 Thread 0xb6ab26f0 (LWP 11288)  0xffffe430 in __kernel_vsyscall ()
(gdb)

If you are interested in the actual unicon code it is:

   while  read() ~== "a" do PlayAudio("opendoor.ogg")