6d1f9a5527b27e8d43247f76afd89e1477113629
[blender-staging.git] / intern / audaspace / OpenAL / AUD_OpenALDevice.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN LGPL LICENSE BLOCK *****
5  *
6  * Copyright 2009 Jörg Hermann Müller
7  *
8  * This file is part of AudaSpace.
9  *
10  * AudaSpace is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * AudaSpace is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * ***** END LGPL LICENSE BLOCK *****
24  */
25
26 #include "AUD_OpenALDevice.h"
27 #include "AUD_IFactory.h"
28 #include "AUD_IReader.h"
29 #include "AUD_ConverterReader.h"
30
31 #include <cstring>
32 #include <limits>
33
34 #ifdef WIN32
35 #include <windows.h>
36 #else
37 #include <unistd.h>
38 #endif
39
40 #define AUD_OPENAL_CYCLE_BUFFERS 3
41
42 /// Saves the data for playback.
43 struct AUD_OpenALHandle : AUD_Handle
44 {
45         /// Whether it's a buffered or a streamed source.
46         bool isBuffered;
47
48         /// The reader source.
49         AUD_IReader* reader;
50
51         /// Whether to keep the source if end of it is reached.
52         bool keep;
53
54         /// OpenAL sample format.
55         ALenum format;
56
57         /// OpenAL source.
58         ALuint source;
59
60         /// OpenAL buffers.
61         ALuint buffers[AUD_OPENAL_CYCLE_BUFFERS];
62
63         /// The first buffer to be read next.
64         int current;
65
66         /// Whether the stream doesn't return any more data.
67         bool data_end;
68 };
69
70 struct AUD_OpenALBufferedFactory
71 {
72         /// The factory.
73         AUD_IFactory* factory;
74
75         /// The OpenAL buffer.
76         ALuint buffer;
77 };
78
79 typedef std::list<AUD_OpenALHandle*>::iterator AUD_HandleIterator;
80 typedef std::list<AUD_OpenALBufferedFactory*>::iterator AUD_BFIterator;
81
82 /******************************************************************************/
83 /**************************** Threading Code **********************************/
84 /******************************************************************************/
85
86 void* AUD_openalRunThread(void* device)
87 {
88         AUD_OpenALDevice* dev = (AUD_OpenALDevice*)device;
89         dev->updateStreams();
90         return NULL;
91 }
92
93 void AUD_OpenALDevice::start()
94 {
95         lock();
96
97         if(!m_playing)
98         {
99                 pthread_attr_t attr;
100                 pthread_attr_init(&attr);
101                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
102
103                 pthread_create(&m_thread, &attr, AUD_openalRunThread, this);
104
105                 pthread_attr_destroy(&attr);
106
107                 m_playing = true;
108         }
109
110         unlock();
111 }
112
113 void AUD_OpenALDevice::updateStreams()
114 {
115         AUD_OpenALHandle* sound;
116
117         int length;
118         sample_t* buffer;
119
120         ALint info;
121         AUD_DeviceSpecs specs = m_specs;
122
123         while(1)
124         {
125                 lock();
126
127                 alcSuspendContext(m_context);
128
129                 {
130                         // for all sounds
131                         AUD_HandleIterator it = m_playingSounds->begin();
132                         while(it != m_playingSounds->end())
133                         {
134                                 sound = *it;
135                                 // increment the iterator to make sure it's valid,
136                                 // in case the sound gets deleted after stopping
137                                 ++it;
138
139                                 // is it a streamed sound?
140                                 if(!sound->isBuffered)
141                                 {
142                                         // check for buffer refilling
143                                         alGetSourcei(sound->source, AL_BUFFERS_PROCESSED, &info);
144
145                                         if(info)
146                                         {
147                                                 specs.specs = sound->reader->getSpecs();
148
149                                                 // for all empty buffers
150                                                 while(info--)
151                                                 {
152                                                         // if there's still data to play back
153                                                         if(!sound->data_end)
154                                                         {
155                                                                 // read data
156                                                                 length = m_buffersize;
157                                                                 sound->reader->read(length, buffer);
158
159                                                                 // read nothing?
160                                                                 if(length == 0)
161                                                                 {
162                                                                         sound->data_end = true;
163                                                                         break;
164                                                                 }
165
166                                                                 // unqueue buffer
167                                                                 alSourceUnqueueBuffers(sound->source, 1,
168                                                                                                 &sound->buffers[sound->current]);
169                                                                 ALenum err;
170                                                                 if((err = alGetError()) != AL_NO_ERROR)
171                                                                 {
172                                                                         sound->data_end = true;
173                                                                         break;
174                                                                 }
175
176                                                                 // fill with new data
177                                                                 alBufferData(sound->buffers[sound->current],
178                                                                                          sound->format,
179                                                                                          buffer, length *
180                                                                                          AUD_DEVICE_SAMPLE_SIZE(specs),
181                                                                                          specs.rate);
182
183                                                                 if((err = alGetError()) != AL_NO_ERROR)
184                                                                 {
185                                                                         sound->data_end = true;
186                                                                         break;
187                                                                 }
188
189                                                                 // and queue again
190                                                                 alSourceQueueBuffers(sound->source, 1,
191                                                                                                 &sound->buffers[sound->current]);
192                                                                 if(alGetError() != AL_NO_ERROR)
193                                                                 {
194                                                                         sound->data_end = true;
195                                                                         break;
196                                                                 }
197
198                                                                 sound->current = (sound->current+1) %
199                                                                                                  AUD_OPENAL_CYCLE_BUFFERS;
200                                                         }
201                                                         else
202                                                                 break;
203                                                 }
204                                         }
205                                 }
206
207                                 // check if the sound has been stopped
208                                 alGetSourcei(sound->source, AL_SOURCE_STATE, &info);
209
210                                 if(info != AL_PLAYING)
211                                 {
212                                         // if it really stopped
213                                         if(sound->data_end)
214                                         {
215                                                 // pause or
216                                                 if(sound->keep)
217                                                         pause(sound);
218                                                 // stop
219                                                 else
220                                                         stop(sound);
221                                         }
222                                         // continue playing
223                                         else
224                                                 alSourcePlay(sound->source);
225                                 }
226                         }
227                 }
228
229                 alcProcessContext(m_context);
230
231                 // stop thread
232                 if(m_playingSounds->empty())
233                 {
234                         unlock();
235                         m_playing = false;
236                         pthread_exit(NULL);
237                 }
238
239                 unlock();
240
241 #ifdef WIN32
242                 Sleep(20);
243 #else
244                 usleep(20000);
245 #endif
246         }
247 }
248
249 /******************************************************************************/
250 /**************************** IDevice Code ************************************/
251 /******************************************************************************/
252
253 bool AUD_OpenALDevice::isValid(AUD_Handle* handle)
254 {
255         for(AUD_HandleIterator i = m_playingSounds->begin();
256                 i != m_playingSounds->end(); i++)
257                 if(*i == handle)
258                         return true;
259         for(AUD_HandleIterator i = m_pausedSounds->begin();
260                 i != m_pausedSounds->end(); i++)
261                 if(*i == handle)
262                         return true;
263         return false;
264 }
265
266 AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
267 {
268         // cannot determine how many channels or which format OpenAL uses, but
269         // it at least is able to play 16 bit stereo audio
270         specs.channels = AUD_CHANNELS_STEREO;
271         specs.format = AUD_FORMAT_S16;
272
273 #if 0
274         if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
275         {
276                 ALCchar* devices = const_cast<ALCchar*>(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
277                 printf("OpenAL devices (standard is: %s):\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
278
279                 while(*devices)
280                 {
281                         printf("%s\n", devices);
282                         devices += strlen(devices) + 1;
283                 }
284         }
285 #endif
286
287         m_device = alcOpenDevice(NULL);
288
289         if(!m_device)
290                 AUD_THROW(AUD_ERROR_OPENAL);
291
292         // at least try to set the frequency
293         ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
294         ALCint* attributes = attribs;
295         if(specs.rate == AUD_RATE_INVALID)
296                 attributes = NULL;
297
298         m_context = alcCreateContext(m_device, attributes);
299         alcMakeContextCurrent(m_context);
300
301         alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);
302
303         // check for specific formats and channel counts to be played back
304         if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
305                 specs.format = AUD_FORMAT_FLOAT32;
306
307         m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;
308
309         alGetError();
310
311         m_specs = specs;
312         m_buffersize = buffersize;
313         m_playing = false;
314
315         m_playingSounds = new std::list<AUD_OpenALHandle*>();
316         m_pausedSounds = new std::list<AUD_OpenALHandle*>();
317         m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();
318
319         pthread_mutexattr_t attr;
320         pthread_mutexattr_init(&attr);
321         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
322
323         pthread_mutex_init(&m_mutex, &attr);
324
325         pthread_mutexattr_destroy(&attr);
326 }
327
328 AUD_OpenALDevice::~AUD_OpenALDevice()
329 {
330         AUD_OpenALHandle* sound;
331
332         lock();
333         alcSuspendContext(m_context);
334
335         // delete all playing sounds
336         while(!m_playingSounds->empty())
337         {
338                 sound = *(m_playingSounds->begin());
339                 alDeleteSources(1, &sound->source);
340                 if(!sound->isBuffered)
341                 {
342                         delete sound->reader;
343                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
344                 }
345                 delete sound;
346                 m_playingSounds->erase(m_playingSounds->begin());
347         }
348
349         // delete all paused sounds
350         while(!m_pausedSounds->empty())
351         {
352                 sound = *(m_pausedSounds->begin());
353                 alDeleteSources(1, &sound->source);
354                 if(!sound->isBuffered)
355                 {
356                         delete sound->reader;
357                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
358                 }
359                 delete sound;
360                 m_pausedSounds->erase(m_pausedSounds->begin());
361         }
362
363         // delete all buffered factories
364         while(!m_bufferedFactories->empty())
365         {
366                 alDeleteBuffers(1, &(*(m_bufferedFactories->begin()))->buffer);
367                 delete *m_bufferedFactories->begin();
368                 m_bufferedFactories->erase(m_bufferedFactories->begin());
369         }
370
371         alcProcessContext(m_context);
372
373         // wait for the thread to stop
374         if(m_playing)
375         {
376                 unlock();
377                 pthread_join(m_thread, NULL);
378         }
379         else
380                 unlock();
381
382         delete m_playingSounds;
383         delete m_pausedSounds;
384         delete m_bufferedFactories;
385
386         // quit OpenAL
387         alcMakeContextCurrent(NULL);
388         alcDestroyContext(m_context);
389         alcCloseDevice(m_device);
390
391         pthread_mutex_destroy(&m_mutex);
392 }
393
394 AUD_DeviceSpecs AUD_OpenALDevice::getSpecs() const
395 {
396         return m_specs;
397 }
398
399 bool AUD_OpenALDevice::getFormat(ALenum &format, AUD_Specs specs)
400 {
401         bool valid = true;
402         format = 0;
403
404         switch(m_specs.format)
405         {
406         case AUD_FORMAT_S16:
407                 switch(specs.channels)
408                 {
409                 case AUD_CHANNELS_MONO:
410                         format = AL_FORMAT_MONO16;
411                         break;
412                 case AUD_CHANNELS_STEREO:
413                         format = AL_FORMAT_STEREO16;
414                         break;
415                 case AUD_CHANNELS_SURROUND4:
416                         if(m_useMC)
417                         {
418                                 format = alGetEnumValue("AL_FORMAT_QUAD16");
419                                 break;
420                         }
421                 case AUD_CHANNELS_SURROUND51:
422                         if(m_useMC)
423                         {
424                                 format = alGetEnumValue("AL_FORMAT_51CHN16");
425                                 break;
426                         }
427                 case AUD_CHANNELS_SURROUND61:
428                         if(m_useMC)
429                         {
430                                 format = alGetEnumValue("AL_FORMAT_61CHN16");
431                                 break;
432                         }
433                 case AUD_CHANNELS_SURROUND71:
434                         if(m_useMC)
435                         {
436                                 format = alGetEnumValue("AL_FORMAT_71CHN16");
437                                 break;
438                         }
439                 default:
440                         valid = false;
441                 }
442                 break;
443         case AUD_FORMAT_FLOAT32:
444                 switch(specs.channels)
445                 {
446                 case AUD_CHANNELS_MONO:
447                         format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
448                         break;
449                 case AUD_CHANNELS_STEREO:
450                         format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
451                         break;
452                 case AUD_CHANNELS_SURROUND4:
453                         if(m_useMC)
454                         {
455                                 format = alGetEnumValue("AL_FORMAT_QUAD32");
456                                 break;
457                         }
458                 case AUD_CHANNELS_SURROUND51:
459                         if(m_useMC)
460                         {
461                                 format = alGetEnumValue("AL_FORMAT_51CHN32");
462                                 break;
463                         }
464                 case AUD_CHANNELS_SURROUND61:
465                         if(m_useMC)
466                         {
467                                 format = alGetEnumValue("AL_FORMAT_61CHN32");
468                                 break;
469                         }
470                 case AUD_CHANNELS_SURROUND71:
471                         if(m_useMC)
472                         {
473                                 format = alGetEnumValue("AL_FORMAT_71CHN32");
474                                 break;
475                         }
476                 default:
477                         valid = false;
478                 }
479                 break;
480         default:
481                 valid = false;
482         }
483
484         if(!format)
485                 valid = false;
486
487         return valid;
488 }
489
490 AUD_Handle* AUD_OpenALDevice::play(AUD_IFactory* factory, bool keep)
491 {
492         lock();
493
494         AUD_OpenALHandle* sound = NULL;
495
496         try
497         {
498                 // check if it is a buffered factory
499                 for(AUD_BFIterator i = m_bufferedFactories->begin();
500                         i != m_bufferedFactories->end(); i++)
501                 {
502                         if((*i)->factory == factory)
503                         {
504                                 // create the handle
505                                 sound = new AUD_OpenALHandle;
506                                 sound->keep = keep;
507                                 sound->current = -1;
508                                 sound->isBuffered = true;
509                                 sound->data_end = true;
510
511                                 alcSuspendContext(m_context);
512
513                                 // OpenAL playback code
514                                 try
515                                 {
516                                         alGenSources(1, &sound->source);
517                                         if(alGetError() != AL_NO_ERROR)
518                                                 AUD_THROW(AUD_ERROR_OPENAL);
519
520                                         try
521                                         {
522                                                 alSourcei(sound->source, AL_BUFFER, (*i)->buffer);
523                                                 if(alGetError() != AL_NO_ERROR)
524                                                         AUD_THROW(AUD_ERROR_OPENAL);
525                                         }
526                                         catch(AUD_Exception&)
527                                         {
528                                                 alDeleteSources(1, &sound->source);
529                                                 throw;
530                                         }
531                                 }
532                                 catch(AUD_Exception&)
533                                 {
534                                         delete sound;
535                                         alcProcessContext(m_context);
536                                         throw;
537                                 }
538
539                                 // play sound
540                                 m_playingSounds->push_back(sound);
541
542                                 alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
543                                 start();
544
545                                 alcProcessContext(m_context);
546                         }
547                 }
548         }
549         catch(AUD_Exception&)
550         {
551                 unlock();
552                 throw;
553         }
554
555         unlock();
556
557         if(sound)
558                 return sound;
559
560         AUD_IReader* reader = factory->createReader();
561
562         if(reader == NULL)
563                 AUD_THROW(AUD_ERROR_READER);
564
565         AUD_DeviceSpecs specs = m_specs;
566         specs.specs = reader->getSpecs();
567
568         // check format
569         bool valid = specs.channels != AUD_CHANNELS_INVALID;
570
571         if(m_specs.format != AUD_FORMAT_FLOAT32)
572                 reader = new AUD_ConverterReader(reader, m_specs);
573
574         // create the handle
575         sound = new AUD_OpenALHandle;
576         sound->keep = keep;
577         sound->reader = reader;
578         sound->current = 0;
579         sound->isBuffered = false;
580         sound->data_end = false;
581
582         valid &= getFormat(sound->format, specs.specs);
583
584         if(!valid)
585         {
586                 delete sound;
587                 delete reader;
588                 return NULL;
589         }
590
591         lock();
592         alcSuspendContext(m_context);
593
594         // OpenAL playback code
595         try
596         {
597                 alGenBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
598                 if(alGetError() != AL_NO_ERROR)
599                         AUD_THROW(AUD_ERROR_OPENAL);
600
601                 try
602                 {
603                         sample_t* buf;
604                         int length;
605
606                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
607                         {
608                                 length = m_buffersize;
609                                 reader->read(length, buf);
610                                 alBufferData(sound->buffers[i], sound->format, buf,
611                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
612                                                          specs.rate);
613                                 if(alGetError() != AL_NO_ERROR)
614                                         AUD_THROW(AUD_ERROR_OPENAL);
615                         }
616
617                         alGenSources(1, &sound->source);
618                         if(alGetError() != AL_NO_ERROR)
619                                 AUD_THROW(AUD_ERROR_OPENAL);
620
621                         try
622                         {
623                                 alSourceQueueBuffers(sound->source, AUD_OPENAL_CYCLE_BUFFERS,
624                                                                          sound->buffers);
625                                 if(alGetError() != AL_NO_ERROR)
626                                         AUD_THROW(AUD_ERROR_OPENAL);
627                         }
628                         catch(AUD_Exception&)
629                         {
630                                 alDeleteSources(1, &sound->source);
631                                 throw;
632                         }
633                 }
634                 catch(AUD_Exception&)
635                 {
636                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
637                         throw;
638                 }
639         }
640         catch(AUD_Exception&)
641         {
642                 delete sound;
643                 delete reader;
644                 alcProcessContext(m_context);
645                 unlock();
646                 throw;
647         }
648
649         // play sound
650         m_playingSounds->push_back(sound);
651         alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
652
653         start();
654
655         alcProcessContext(m_context);
656         unlock();
657
658         return sound;
659 }
660
661 bool AUD_OpenALDevice::pause(AUD_Handle* handle)
662 {
663         bool result = false;
664
665         lock();
666
667         // only songs that are played can be paused
668         for(AUD_HandleIterator i = m_playingSounds->begin();
669                 i != m_playingSounds->end(); i++)
670         {
671                 if(*i == handle)
672                 {
673                         m_pausedSounds->push_back(*i);
674                         alSourcePause((*i)->source);
675                         m_playingSounds->erase(i);
676                         result = true;
677                         break;
678                 }
679         }
680
681         unlock();
682
683         return result;
684 }
685
686 bool AUD_OpenALDevice::resume(AUD_Handle* handle)
687 {
688         bool result = false;
689
690         lock();
691
692         // only songs that are paused can be resumed
693         for(AUD_HandleIterator i = m_pausedSounds->begin();
694                 i != m_pausedSounds->end(); i++)
695         {
696                 if(*i == handle)
697                 {
698                         m_playingSounds->push_back(*i);
699                         start();
700                         m_pausedSounds->erase(i);
701                         result = true;
702                         break;
703                 }
704         }
705
706         unlock();
707
708         return result;
709 }
710
711 bool AUD_OpenALDevice::stop(AUD_Handle* handle)
712 {
713         AUD_OpenALHandle* sound;
714
715         bool result = false;
716
717         lock();
718
719         for(AUD_HandleIterator i = m_playingSounds->begin();
720                 i != m_playingSounds->end(); i++)
721         {
722                 if(*i == handle)
723                 {
724                         sound = *i;
725                         alDeleteSources(1, &sound->source);
726                         if(!sound->isBuffered)
727                         {
728                                 delete sound->reader;
729                                 alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
730                         }
731                         delete *i;
732                         m_playingSounds->erase(i);
733                         result = true;
734                         break;
735                 }
736         }
737         if(!result)
738         {
739                 for(AUD_HandleIterator i = m_pausedSounds->begin();
740                         i != m_pausedSounds->end(); i++)
741                 {
742                         if(*i == handle)
743                         {
744                                 sound = *i;
745                                 alDeleteSources(1, &sound->source);
746                                 if(!sound->isBuffered)
747                                 {
748                                         delete sound->reader;
749                                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
750                                 }
751                                 delete *i;
752                                 m_pausedSounds->erase(i);
753                                 result = true;
754                                 break;
755                         }
756                 }
757         }
758
759         unlock();
760
761         return result;
762 }
763
764 bool AUD_OpenALDevice::getKeep(AUD_Handle* handle)
765 {
766         bool result = false;
767
768         lock();
769
770         if(isValid(handle))
771                 result = ((AUD_OpenALHandle*)handle)->keep;
772
773         unlock();
774
775         return result;
776 }
777
778 bool AUD_OpenALDevice::setKeep(AUD_Handle* handle, bool keep)
779 {
780         bool result = false;
781
782         lock();
783
784         if(isValid(handle))
785         {
786                 ((AUD_OpenALHandle*)handle)->keep = keep;
787                 result = true;
788         }
789
790         unlock();
791
792         return result;
793 }
794
795 bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position)
796 {
797         bool result = false;
798
799         lock();
800
801         if(isValid(handle))
802         {
803                 AUD_OpenALHandle* alhandle = (AUD_OpenALHandle*)handle;
804                 if(alhandle->isBuffered)
805                         alSourcef(alhandle->source, AL_SEC_OFFSET, position);
806                 else
807                 {
808                         alhandle->reader->seek((int)(position *
809                                                                                  alhandle->reader->getSpecs().rate));
810                         alhandle->data_end = false;
811
812                         ALint info;
813
814                         alGetSourcei(alhandle->source, AL_SOURCE_STATE, &info);
815
816                         if(info != AL_PLAYING)
817                         {
818                                 if(info == AL_PAUSED)
819                                         alSourceStop(alhandle->source);
820
821                                 alSourcei(alhandle->source, AL_BUFFER, 0);
822                                 alhandle->current = 0;
823
824                                 ALenum err;
825                                 if((err = alGetError()) == AL_NO_ERROR)
826                                 {
827                                         sample_t* buf;
828                                         int length;
829                                         AUD_DeviceSpecs specs = m_specs;
830                                         specs.specs = alhandle->reader->getSpecs();
831
832                                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
833                                         {
834                                                 length = m_buffersize;
835                                                 alhandle->reader->read(length, buf);
836                                                 alBufferData(alhandle->buffers[i], alhandle->format,
837                                                                          buf,
838                                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
839                                                                          specs.rate);
840
841                                                 if(alGetError() != AL_NO_ERROR)
842                                                         break;
843                                         }
844
845                                         alSourceQueueBuffers(alhandle->source,
846                                                                                  AUD_OPENAL_CYCLE_BUFFERS,
847                                                                                  alhandle->buffers);
848                                 }
849
850                                 alSourceRewind(alhandle->source);
851                         }
852                 }
853                 result = true;
854         }
855
856         unlock();
857         return result;
858 }
859
860 float AUD_OpenALDevice::getPosition(AUD_Handle* handle)
861 {
862         float position = 0.0f;
863
864         lock();
865
866         if(isValid(handle))
867         {
868                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
869                 alGetSourcef(h->source, AL_SEC_OFFSET, &position);
870                 if(!h->isBuffered)
871                 {
872                         AUD_Specs specs = h->reader->getSpecs();
873                         position += (h->reader->getPosition() - m_buffersize *
874                                                                         AUD_OPENAL_CYCLE_BUFFERS) /
875                                            (float)specs.rate;
876                 }
877         }
878
879         unlock();
880         return position;
881 }
882
883 AUD_Status AUD_OpenALDevice::getStatus(AUD_Handle* handle)
884 {
885         AUD_Status status = AUD_STATUS_INVALID;
886
887         lock();
888
889         for(AUD_HandleIterator i = m_playingSounds->begin();
890                 i != m_playingSounds->end(); i++)
891         {
892                 if(*i == handle)
893                 {
894                         status = AUD_STATUS_PLAYING;
895                         break;
896                 }
897         }
898         if(status == AUD_STATUS_INVALID)
899         {
900                 for(AUD_HandleIterator i = m_pausedSounds->begin();
901                         i != m_pausedSounds->end(); i++)
902                 {
903                         if(*i == handle)
904                         {
905                                 status = AUD_STATUS_PAUSED;
906                                 break;
907                         }
908                 }
909         }
910
911         unlock();
912
913         return status;
914 }
915
916 void AUD_OpenALDevice::lock()
917 {
918         pthread_mutex_lock(&m_mutex);
919 }
920
921 void AUD_OpenALDevice::unlock()
922 {
923         pthread_mutex_unlock(&m_mutex);
924 }
925
926 float AUD_OpenALDevice::getVolume() const
927 {
928         float result;
929         alGetListenerf(AL_GAIN, &result);
930         return result;
931 }
932
933 void AUD_OpenALDevice::setVolume(float volume)
934 {
935         alListenerf(AL_GAIN, volume);
936 }
937
938 float AUD_OpenALDevice::getVolume(AUD_Handle* handle)
939 {
940         lock();
941         float result = std::numeric_limits<float>::quiet_NaN();
942         if(isValid(handle))
943                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_GAIN, &result);
944         unlock();
945         return result;
946 }
947
948 bool AUD_OpenALDevice::setVolume(AUD_Handle* handle, float volume)
949 {
950         lock();
951         bool result = isValid(handle);
952         if(result)
953                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_GAIN, volume);
954         unlock();
955         return result;
956 }
957
958 float AUD_OpenALDevice::getPitch(AUD_Handle* handle)
959 {
960         lock();
961         float result = std::numeric_limits<float>::quiet_NaN();
962         if(isValid(handle))
963                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_PITCH, &result);
964         unlock();
965         return result;
966 }
967
968 bool AUD_OpenALDevice::setPitch(AUD_Handle* handle, float pitch)
969 {
970         lock();
971         bool result = isValid(handle);
972         if(result)
973                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_PITCH, pitch);
974         unlock();
975         return result;
976 }
977
978 /* AUD_XXX Temorary disabled
979
980 bool AUD_OpenALDevice::bufferFactory(void *value)
981 {
982         bool result = false;
983         AUD_IFactory* factory = (AUD_IFactory*) value;
984
985         // load the factory into an OpenAL buffer
986         if(factory)
987         {
988                 // check if the factory is already buffered
989                 lock();
990                 for(AUD_BFIterator i = m_bufferedFactories->begin();
991                         i != m_bufferedFactories->end(); i++)
992                 {
993                         if((*i)->factory == factory)
994                         {
995                                 result = true;
996                                 break;
997                         }
998                 }
999                 unlock();
1000                 if(result)
1001                         return result;
1002
1003                 AUD_IReader* reader = factory->createReader();
1004
1005                 if(reader == NULL)
1006                         return false;
1007
1008                 AUD_DeviceSpecs specs = m_specs;
1009                 specs.specs = reader->getSpecs();
1010
1011                 if(m_specs.format != AUD_FORMAT_FLOAT32)
1012                         reader = new AUD_ConverterReader(reader, m_specs);
1013
1014                 ALenum format;
1015
1016                 if(!getFormat(format, specs.specs))
1017                 {
1018                         delete reader;
1019                         return false;
1020                 }
1021
1022                 // load into a buffer
1023                 lock();
1024                 alcSuspendContext(m_context);
1025
1026                 AUD_OpenALBufferedFactory* bf = new AUD_OpenALBufferedFactory;
1027                 bf->factory = factory;
1028
1029                 try
1030                 {
1031                         alGenBuffers(1, &bf->buffer);
1032                         if(alGetError() != AL_NO_ERROR)
1033                                 AUD_THROW(AUD_ERROR_OPENAL);
1034
1035                         try
1036                         {
1037                                 sample_t* buf;
1038                                 int length = reader->getLength();
1039
1040                                 reader->read(length, buf);
1041                                 alBufferData(bf->buffer, format, buf,
1042                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
1043                                                          specs.rate);
1044                                 if(alGetError() != AL_NO_ERROR)
1045                                         AUD_THROW(AUD_ERROR_OPENAL);
1046                         }
1047                         catch(AUD_Exception&)
1048                         {
1049                                 alDeleteBuffers(1, &bf->buffer);
1050                                 throw;
1051                         }
1052                 }
1053                 catch(AUD_Exception&)
1054                 {
1055                         delete bf;
1056                         delete reader;
1057                         alcProcessContext(m_context);
1058                         unlock();
1059                         return false;
1060                 }
1061
1062                 m_bufferedFactories->push_back(bf);
1063
1064                 alcProcessContext(m_context);
1065                 unlock();
1066         }
1067         else
1068         {
1069                 // stop all playing and paused buffered sources
1070                 lock();
1071                 alcSuspendContext(m_context);
1072
1073                 AUD_OpenALHandle* sound;
1074                 AUD_HandleIterator it = m_playingSounds->begin();
1075                 while(it != m_playingSounds->end())
1076                 {
1077                         sound = *it;
1078                         ++it;
1079
1080                         if(sound->isBuffered)
1081                                 stop(sound);
1082                 }
1083                 alcProcessContext(m_context);
1084
1085                 while(!m_bufferedFactories->empty())
1086                 {
1087                         alDeleteBuffers(1,
1088                                                         &(*(m_bufferedFactories->begin()))->buffer);
1089                         delete *m_bufferedFactories->begin();
1090                         m_bufferedFactories->erase(m_bufferedFactories->begin());
1091                 }
1092                 unlock();
1093         }
1094
1095         return true;
1096 }*/
1097
1098 /******************************************************************************/
1099 /**************************** 3D Device Code **********************************/
1100 /******************************************************************************/
1101
1102 AUD_Vector3 AUD_OpenALDevice::getListenerLocation() const
1103 {
1104         ALfloat p[3];
1105         alGetListenerfv(AL_POSITION, p);
1106         return AUD_Vector3(p[0], p[1], p[2]);
1107 }
1108
1109 void AUD_OpenALDevice::setListenerLocation(const AUD_Vector3& location)
1110 {
1111         alListenerfv(AL_POSITION, (ALfloat*)location.get());
1112 }
1113
1114 AUD_Vector3 AUD_OpenALDevice::getListenerVelocity() const
1115 {
1116         ALfloat v[3];
1117         alGetListenerfv(AL_VELOCITY, v);
1118         return AUD_Vector3(v[0], v[1], v[2]);
1119 }
1120
1121 void AUD_OpenALDevice::setListenerVelocity(const AUD_Vector3& velocity)
1122 {
1123         alListenerfv(AL_VELOCITY, (ALfloat*)velocity.get());
1124 }
1125
1126 AUD_Quaternion AUD_OpenALDevice::getListenerOrientation() const
1127 {
1128         // AUD_XXX not implemented yet
1129         return AUD_Quaternion(0, 0, 0, 0);
1130 }
1131
1132 void AUD_OpenALDevice::setListenerOrientation(const AUD_Quaternion& orientation)
1133 {
1134         ALfloat direction[6];
1135         direction[0] = -2 * (orientation.w() * orientation.y() +
1136                                                  orientation.x() * orientation.z());
1137         direction[1] = 2 * (orientation.x() * orientation.w() -
1138                                                 orientation.z() * orientation.y());
1139         direction[2] = 2 * (orientation.x() * orientation.x() +
1140                                                 orientation.y() * orientation.y()) - 1;
1141         direction[3] = 2 * (orientation.x() * orientation.y() -
1142                                                 orientation.w() * orientation.z());
1143         direction[4] = 1 - 2 * (orientation.x() * orientation.x() +
1144                                                         orientation.z() * orientation.z());
1145         direction[5] = 2 * (orientation.w() * orientation.x() +
1146                                                 orientation.y() * orientation.z());
1147         alListenerfv(AL_ORIENTATION, direction);
1148 }
1149
1150 float AUD_OpenALDevice::getSpeedOfSound() const
1151 {
1152         return alGetFloat(AL_SPEED_OF_SOUND);
1153 }
1154
1155 void AUD_OpenALDevice::setSpeedOfSound(float speed)
1156 {
1157         alSpeedOfSound(speed);
1158 }
1159
1160 float AUD_OpenALDevice::getDopplerFactor() const
1161 {
1162         return alGetFloat(AL_DOPPLER_FACTOR);
1163 }
1164
1165 void AUD_OpenALDevice::setDopplerFactor(float factor)
1166 {
1167         alDopplerFactor(factor);
1168 }
1169
1170 AUD_DistanceModel AUD_OpenALDevice::getDistanceModel() const
1171 {
1172         switch(alGetInteger(AL_DISTANCE_MODEL))
1173         {
1174         case AL_INVERSE_DISTANCE:
1175                 return AUD_DISTANCE_MODEL_INVERSE;
1176         case AL_INVERSE_DISTANCE_CLAMPED:
1177                 return AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
1178         case AL_LINEAR_DISTANCE:
1179                 return AUD_DISTANCE_MODEL_LINEAR;
1180         case AL_LINEAR_DISTANCE_CLAMPED:
1181                 return AUD_DISTANCE_MODEL_LINEAR_CLAMPED;
1182         case AL_EXPONENT_DISTANCE:
1183                 return AUD_DISTANCE_MODEL_EXPONENT;
1184         case AL_EXPONENT_DISTANCE_CLAMPED:
1185                 return AUD_DISTANCE_MODEL_EXPONENT_CLAMPED;
1186         default:
1187                 return AUD_DISTANCE_MODEL_INVALID;
1188         }
1189 }
1190
1191 void AUD_OpenALDevice::setDistanceModel(AUD_DistanceModel model)
1192 {
1193         switch(model)
1194         {
1195         case AUD_DISTANCE_MODEL_INVERSE:
1196                 alDistanceModel(AL_INVERSE_DISTANCE);
1197                 break;
1198         case AUD_DISTANCE_MODEL_INVERSE_CLAMPED:
1199                 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
1200                 break;
1201         case AUD_DISTANCE_MODEL_LINEAR:
1202                 alDistanceModel(AL_LINEAR_DISTANCE);
1203                 break;
1204         case AUD_DISTANCE_MODEL_LINEAR_CLAMPED:
1205                 alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
1206                 break;
1207         case AUD_DISTANCE_MODEL_EXPONENT:
1208                 alDistanceModel(AL_EXPONENT_DISTANCE);
1209                 break;
1210         case AUD_DISTANCE_MODEL_EXPONENT_CLAMPED:
1211                 alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
1212                 break;
1213         default:
1214                 alDistanceModel(AL_NONE);
1215         }
1216 }
1217
1218 AUD_Vector3 AUD_OpenALDevice::getSourceLocation(AUD_Handle* handle)
1219 {
1220         AUD_Vector3 result = AUD_Vector3(0, 0, 0);
1221         ALfloat p[3];
1222         lock();
1223
1224         if(isValid(handle))
1225         {
1226                 alGetSourcefv(((AUD_OpenALHandle*)handle)->source, AL_POSITION, p);
1227                 result = AUD_Vector3(p[0], p[1], p[2]);
1228         }
1229
1230         unlock();
1231         return result;
1232 }
1233
1234 bool AUD_OpenALDevice::setSourceLocation(AUD_Handle* handle, const AUD_Vector3& location)
1235 {
1236         lock();
1237         bool result = isValid(handle);
1238
1239         if(result)
1240                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_POSITION,
1241                                    (ALfloat*)location.get());
1242
1243         unlock();
1244         return result;
1245 }
1246
1247 AUD_Vector3 AUD_OpenALDevice::getSourceVelocity(AUD_Handle* handle)
1248 {
1249         AUD_Vector3 result = AUD_Vector3(0, 0, 0);
1250         ALfloat v[3];
1251         lock();
1252
1253         if(isValid(handle))
1254         {
1255                 alGetSourcefv(((AUD_OpenALHandle*)handle)->source, AL_VELOCITY, v);
1256                 result = AUD_Vector3(v[0], v[1], v[2]);
1257         }
1258
1259         unlock();
1260         return result;
1261 }
1262
1263 bool AUD_OpenALDevice::setSourceVelocity(AUD_Handle* handle, const AUD_Vector3& velocity)
1264 {
1265         lock();
1266         bool result = isValid(handle);
1267
1268         if(result)
1269                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_VELOCITY,
1270                                    (ALfloat*)velocity.get());
1271
1272         unlock();
1273         return result;
1274 }
1275
1276 AUD_Quaternion AUD_OpenALDevice::getSourceOrientation(AUD_Handle* handle)
1277 {
1278         // AUD_XXX not implemented yet
1279         return AUD_Quaternion(0, 0, 0, 0);
1280 }
1281
1282 bool AUD_OpenALDevice::setSourceOrientation(AUD_Handle* handle, const AUD_Quaternion& orientation)
1283 {
1284         lock();
1285         bool result = isValid(handle);
1286
1287         if(result)
1288         {
1289                 ALfloat direction[3];
1290                 direction[0] = -2 * (orientation.w() * orientation.y() +
1291                                                          orientation.x() * orientation.z());
1292                 direction[1] = 2 * (orientation.x() * orientation.w() -
1293                                                         orientation.z() * orientation.y());
1294                 direction[2] = 2 * (orientation.x() * orientation.x() +
1295                                                         orientation.y() * orientation.y()) - 1;
1296                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_DIRECTION,
1297                                    direction);
1298         }
1299
1300         unlock();
1301         return result;
1302 }
1303
1304 bool AUD_OpenALDevice::isRelative(AUD_Handle* handle)
1305 {
1306         int result = std::numeric_limits<float>::quiet_NaN();;
1307
1308         lock();
1309
1310         if(isValid(handle))
1311                 alGetSourcei(((AUD_OpenALHandle*)handle)->source, AL_SOURCE_RELATIVE,
1312                                          &result);
1313
1314         unlock();
1315         return result;
1316 }
1317
1318 bool AUD_OpenALDevice::setRelative(AUD_Handle* handle, bool relative)
1319 {
1320         lock();
1321         bool result = isValid(handle);
1322
1323         if(result)
1324                 alSourcei(((AUD_OpenALHandle*)handle)->source, AL_SOURCE_RELATIVE,
1325                                   relative);
1326
1327         unlock();
1328         return result;
1329 }
1330
1331 float AUD_OpenALDevice::getVolumeMaximum(AUD_Handle* handle)
1332 {
1333         float result = std::numeric_limits<float>::quiet_NaN();;
1334
1335         lock();
1336
1337         if(isValid(handle))
1338                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_GAIN,
1339                                          &result);
1340
1341         unlock();
1342         return result;
1343 }
1344
1345 bool AUD_OpenALDevice::setVolumeMaximum(AUD_Handle* handle, float volume)
1346 {
1347         lock();
1348         bool result = isValid(handle);
1349
1350         if(result)
1351
1352                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_GAIN,
1353                                   volume);
1354
1355         unlock();
1356         return result;
1357 }
1358
1359 float AUD_OpenALDevice::getVolumeMinimum(AUD_Handle* handle)
1360 {
1361         float result = std::numeric_limits<float>::quiet_NaN();;
1362
1363         lock();
1364
1365         if(isValid(handle))
1366                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MIN_GAIN,
1367                                          &result);
1368
1369         unlock();
1370         return result;
1371 }
1372
1373 bool AUD_OpenALDevice::setVolumeMinimum(AUD_Handle* handle, float volume)
1374 {
1375         lock();
1376         bool result = isValid(handle);
1377
1378         if(result)
1379                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MIN_GAIN,
1380                                   volume);
1381
1382         unlock();
1383         return result;
1384 }
1385
1386 float AUD_OpenALDevice::getDistanceMaximum(AUD_Handle* handle)
1387 {
1388         float result = std::numeric_limits<float>::quiet_NaN();;
1389
1390         lock();
1391
1392         if(isValid(handle))
1393                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_DISTANCE,
1394                                          &result);
1395
1396         unlock();
1397         return result;
1398 }
1399
1400 bool AUD_OpenALDevice::setDistanceMaximum(AUD_Handle* handle, float distance)
1401 {
1402         lock();
1403         bool result = isValid(handle);
1404
1405         if(result)
1406                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_DISTANCE,
1407                                   distance);
1408
1409         unlock();
1410         return result;
1411 }
1412
1413 float AUD_OpenALDevice::getDistanceReference(AUD_Handle* handle)
1414 {
1415         float result = std::numeric_limits<float>::quiet_NaN();;
1416
1417         lock();
1418
1419         if(isValid(handle))
1420                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_REFERENCE_DISTANCE,
1421                                          &result);
1422
1423         unlock();
1424         return result;
1425 }
1426
1427 bool AUD_OpenALDevice::setDistanceReference(AUD_Handle* handle, float distance)
1428 {
1429         lock();
1430         bool result = isValid(handle);
1431
1432         if(result)
1433                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_REFERENCE_DISTANCE,
1434                                   distance);
1435
1436         unlock();
1437         return result;
1438 }
1439
1440 float AUD_OpenALDevice::getAttenuation(AUD_Handle* handle)
1441 {
1442         float result = std::numeric_limits<float>::quiet_NaN();;
1443
1444         lock();
1445
1446         if(isValid(handle))
1447                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_ROLLOFF_FACTOR,
1448                                          &result);
1449
1450         unlock();
1451         return result;
1452 }
1453
1454 bool AUD_OpenALDevice::setAttenuation(AUD_Handle* handle, float factor)
1455 {
1456         lock();
1457         bool result = isValid(handle);
1458
1459         if(result)
1460                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_ROLLOFF_FACTOR,
1461                                   factor);
1462
1463         unlock();
1464         return result;
1465 }
1466
1467 float AUD_OpenALDevice::getConeAngleOuter(AUD_Handle* handle)
1468 {
1469         float result = std::numeric_limits<float>::quiet_NaN();;
1470
1471         lock();
1472
1473         if(isValid(handle))
1474                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_ANGLE,
1475                                          &result);
1476
1477         unlock();
1478         return result;
1479 }
1480
1481 bool AUD_OpenALDevice::setConeAngleOuter(AUD_Handle* handle, float angle)
1482 {
1483         lock();
1484         bool result = isValid(handle);
1485
1486         if(result)
1487                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_ANGLE,
1488                                   angle);
1489
1490         unlock();
1491         return result;
1492 }
1493
1494 float AUD_OpenALDevice::getConeAngleInner(AUD_Handle* handle)
1495 {
1496         float result = std::numeric_limits<float>::quiet_NaN();;
1497
1498         lock();
1499
1500         if(isValid(handle))
1501                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_INNER_ANGLE,
1502                                          &result);
1503
1504         unlock();
1505         return result;
1506 }
1507
1508 bool AUD_OpenALDevice::setConeAngleInner(AUD_Handle* handle, float angle)
1509 {
1510         lock();
1511         bool result = isValid(handle);
1512
1513         if(result)
1514                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_INNER_ANGLE,
1515                                   angle);
1516
1517         unlock();
1518         return result;
1519 }
1520
1521 float AUD_OpenALDevice::getConeVolumeOuter(AUD_Handle* handle)
1522 {
1523         float result = std::numeric_limits<float>::quiet_NaN();;
1524
1525         lock();
1526
1527         if(isValid(handle))
1528                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_GAIN,
1529                                          &result);
1530
1531         unlock();
1532         return result;
1533 }
1534
1535 bool AUD_OpenALDevice::setConeVolumeOuter(AUD_Handle* handle, float volume)
1536 {
1537         lock();
1538         bool result = isValid(handle);
1539
1540         if(result)
1541                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_GAIN,
1542                                   volume);
1543
1544         unlock();
1545         return result;
1546 }