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