465ad5b5ae6f53fc28b606597f5ed6c7802ea7e8
[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_Reference<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 eos;
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
134         ALint info;
135         AUD_DeviceSpecs specs = m_specs;
136         ALCenum cerr;
137         std::list<AUD_OpenALHandle*> stopSounds;
138         std::list<AUD_OpenALHandle*> pauseSounds;
139         AUD_HandleIterator it;
140
141         while(1)
142         {
143                 lock();
144
145                 alcSuspendContext(m_context);
146                 cerr = alcGetError(m_device);
147                 if(cerr == ALC_NO_ERROR)
148                 {
149                         // for all sounds
150                         for(it = m_playingSounds->begin(); it != m_playingSounds->end(); it++)
151                         {
152                                 sound = *it;
153
154                                 // is it a streamed sound?
155                                 if(!sound->isBuffered)
156                                 {
157                                         // check for buffer refilling
158                                         alGetSourcei(sound->source, AL_BUFFERS_PROCESSED, &info);
159
160                                         if(info)
161                                         {
162                                                 specs.specs = sound->reader->getSpecs();
163                                                 m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
164
165                                                 // for all empty buffers
166                                                 while(info--)
167                                                 {
168                                                         // if there's still data to play back
169                                                         if(!sound->eos)
170                                                         {
171                                                                 // read data
172                                                                 length = m_buffersize;
173                                                                 sound->reader->read(length, sound->eos, m_buffer.getBuffer());
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, sound->eos, m_buffer.getBuffer());
185                                                                 }
186
187                                                                 if(sound->loopcount != 0)
188                                                                         sound->eos = false;
189
190                                                                 // read nothing?
191                                                                 if(length == 0)
192                                                                 {
193                                                                         break;
194                                                                 }
195
196                                                                 // unqueue buffer
197                                                                 alSourceUnqueueBuffers(sound->source, 1,
198                                                                                                 &sound->buffers[sound->current]);
199                                                                 ALenum err;
200                                                                 if((err = alGetError()) != AL_NO_ERROR)
201                                                                 {
202                                                                         sound->eos = true;
203                                                                         break;
204                                                                 }
205
206                                                                 // fill with new data
207                                                                 alBufferData(sound->buffers[sound->current],
208                                                                                          sound->format,
209                                                                                          m_buffer.getBuffer(), length *
210                                                                                          AUD_DEVICE_SAMPLE_SIZE(specs),
211                                                                                          specs.rate);
212
213                                                                 if((err = alGetError()) != AL_NO_ERROR)
214                                                                 {
215                                                                         sound->eos = true;
216                                                                         break;
217                                                                 }
218
219                                                                 // and queue again
220                                                                 alSourceQueueBuffers(sound->source, 1,
221                                                                                                 &sound->buffers[sound->current]);
222                                                                 if(alGetError() != AL_NO_ERROR)
223                                                                 {
224                                                                         sound->eos = true;
225                                                                         break;
226                                                                 }
227
228                                                                 sound->current = (sound->current+1) %
229                                                                                                  AUD_OPENAL_CYCLE_BUFFERS;
230                                                         }
231                                                         else
232                                                                 break;
233                                                 }
234                                         }
235                                 }
236
237                                 // check if the sound has been stopped
238                                 alGetSourcei(sound->source, AL_SOURCE_STATE, &info);
239
240                                 if(info != AL_PLAYING)
241                                 {
242                                         // if it really stopped
243                                         if(sound->eos)
244                                         {
245                                                 if(sound->stop)
246                                                         sound->stop(sound->stop_data);
247
248                                                 // pause or
249                                                 if(sound->keep)
250                                                         pauseSounds.push_back(sound);
251                                                 // stop
252                                                 else
253                                                         stopSounds.push_back(sound);
254                                         }
255                                         // continue playing
256                                         else
257                                                 alSourcePlay(sound->source);
258                                 }
259                         }
260
261                         for(it = pauseSounds.begin(); it != pauseSounds.end(); it++)
262                                 pause(*it);
263
264                         for(it = stopSounds.begin(); it != stopSounds.end(); it++)
265                                 stop(*it);
266
267                         pauseSounds.clear();
268                         stopSounds.clear();
269
270                         alcProcessContext(m_context);
271                 }
272
273                 // stop thread
274                 if(m_playingSounds->empty() || (cerr != ALC_NO_ERROR))
275                 {
276                         unlock();
277                         m_playing = false;
278                         pthread_exit(NULL);
279                 }
280
281                 unlock();
282
283 #ifdef WIN32
284                 Sleep(20);
285 #else
286                 usleep(20000);
287 #endif
288         }
289 }
290
291 /******************************************************************************/
292 /**************************** IDevice Code ************************************/
293 /******************************************************************************/
294
295 bool AUD_OpenALDevice::isValid(AUD_Handle* handle)
296 {
297         for(AUD_HandleIterator i = m_playingSounds->begin();
298                 i != m_playingSounds->end(); i++)
299                 if(*i == handle)
300                         return true;
301         for(AUD_HandleIterator i = m_pausedSounds->begin();
302                 i != m_pausedSounds->end(); i++)
303                 if(*i == handle)
304                         return true;
305         return false;
306 }
307
308 static const char* open_error = "AUD_OpenALDevice: Device couldn't be opened.";
309
310 AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
311 {
312         // cannot determine how many channels or which format OpenAL uses, but
313         // it at least is able to play 16 bit stereo audio
314         specs.channels = AUD_CHANNELS_STEREO;
315         specs.format = AUD_FORMAT_S16;
316
317 #if 0
318         if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
319         {
320                 ALCchar* devices = const_cast<ALCchar*>(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
321                 printf("OpenAL devices (standard is: %s):\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
322
323                 while(*devices)
324                 {
325                         printf("%s\n", devices);
326                         devices += strlen(devices) + 1;
327                 }
328         }
329 #endif
330
331         m_device = alcOpenDevice(NULL);
332
333         if(!m_device)
334                 AUD_THROW(AUD_ERROR_OPENAL, open_error);
335
336         // at least try to set the frequency
337         ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
338         ALCint* attributes = attribs;
339         if(specs.rate == AUD_RATE_INVALID)
340                 attributes = NULL;
341
342         m_context = alcCreateContext(m_device, attributes);
343         alcMakeContextCurrent(m_context);
344
345         alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);
346
347         // check for specific formats and channel counts to be played back
348         if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
349                 specs.format = AUD_FORMAT_FLOAT32;
350
351         m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;
352
353         alGetError();
354         alcGetError(m_device);
355
356         m_specs = specs;
357         m_buffersize = buffersize;
358         m_playing = false;
359
360         m_playingSounds = new std::list<AUD_OpenALHandle*>();
361         m_pausedSounds = new std::list<AUD_OpenALHandle*>();
362         m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();
363
364         pthread_mutexattr_t attr;
365         pthread_mutexattr_init(&attr);
366         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
367
368         pthread_mutex_init(&m_mutex, &attr);
369
370         pthread_mutexattr_destroy(&attr);
371 }
372
373 AUD_OpenALDevice::~AUD_OpenALDevice()
374 {
375         AUD_OpenALHandle* sound;
376
377         lock();
378         alcSuspendContext(m_context);
379
380         // delete all playing sounds
381         while(!m_playingSounds->empty())
382         {
383                 sound = *(m_playingSounds->begin());
384                 alDeleteSources(1, &sound->source);
385                 if(!sound->isBuffered)
386                 {
387                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
388                 }
389                 delete sound;
390                 m_playingSounds->erase(m_playingSounds->begin());
391         }
392
393         // delete all paused sounds
394         while(!m_pausedSounds->empty())
395         {
396                 sound = *(m_pausedSounds->begin());
397                 alDeleteSources(1, &sound->source);
398                 if(!sound->isBuffered)
399                 {
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_Reference<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->loopcount = 0;
562         sound->stop = NULL;
563         sound->stop_data = NULL;
564
565         valid &= getFormat(sound->format, specs.specs);
566
567         if(!valid)
568         {
569                 delete sound;
570                 return NULL;
571         }
572
573         lock();
574         alcSuspendContext(m_context);
575
576         // OpenAL playback code
577         try
578         {
579                 alGenBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
580                 if(alGetError() != AL_NO_ERROR)
581                         AUD_THROW(AUD_ERROR_OPENAL, genbuffer_error);
582
583                 try
584                 {
585                         m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
586                         int length;
587
588                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
589                         {
590                                 length = m_buffersize;
591                                 reader->read(length,sound->eos, m_buffer.getBuffer());
592                                 alBufferData(sound->buffers[i], sound->format, m_buffer.getBuffer(),
593                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
594                                                          specs.rate);
595                                 if(alGetError() != AL_NO_ERROR)
596                                         AUD_THROW(AUD_ERROR_OPENAL, bufferdata_error);
597                         }
598
599                         alGenSources(1, &sound->source);
600                         if(alGetError() != AL_NO_ERROR)
601                                 AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
602
603                         try
604                         {
605                                 alSourceQueueBuffers(sound->source, AUD_OPENAL_CYCLE_BUFFERS,
606                                                                          sound->buffers);
607                                 if(alGetError() != AL_NO_ERROR)
608                                         AUD_THROW(AUD_ERROR_OPENAL, queue_error);
609                         }
610                         catch(AUD_Exception&)
611                         {
612                                 alDeleteSources(1, &sound->source);
613                                 throw;
614                         }
615                 }
616                 catch(AUD_Exception&)
617                 {
618                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
619                         throw;
620                 }
621         }
622         catch(AUD_Exception&)
623         {
624                 delete sound;
625                 alcProcessContext(m_context);
626                 unlock();
627                 throw;
628         }
629
630         // play sound
631         m_playingSounds->push_back(sound);
632         alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
633
634         start();
635
636         alcProcessContext(m_context);
637         unlock();
638
639         return sound;
640 }
641
642 AUD_Handle* AUD_OpenALDevice::play(AUD_Reference<AUD_IFactory> factory, bool keep)
643 {
644         /* AUD_XXX disabled
645         AUD_OpenALHandle* sound = NULL;
646
647         lock();
648
649         try
650         {
651                 // check if it is a buffered factory
652                 for(AUD_BFIterator i = m_bufferedFactories->begin();
653                         i != m_bufferedFactories->end(); i++)
654                 {
655                         if((*i)->factory == factory)
656                         {
657                                 // create the handle
658                                 sound = new AUD_OpenALHandle;
659                                 sound->keep = keep;
660                                 sound->current = -1;
661                                 sound->isBuffered = true;
662                                 sound->eos = true;
663                                 sound->loopcount = 0;
664                                 sound->stop = NULL;
665                                 sound->stop_data = NULL;
666
667                                 alcSuspendContext(m_context);
668
669                                 // OpenAL playback code
670                                 try
671                                 {
672                                         alGenSources(1, &sound->source);
673                                         if(alGetError() != AL_NO_ERROR)
674                                                 AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
675
676                                         try
677                                         {
678                                                 alSourcei(sound->source, AL_BUFFER, (*i)->buffer);
679                                                 if(alGetError() != AL_NO_ERROR)
680                                                         AUD_THROW(AUD_ERROR_OPENAL, queue_error);
681                                         }
682                                         catch(AUD_Exception&)
683                                         {
684                                                 alDeleteSources(1, &sound->source);
685                                                 throw;
686                                         }
687                                 }
688                                 catch(AUD_Exception&)
689                                 {
690                                         delete sound;
691                                         alcProcessContext(m_context);
692                                         throw;
693                                 }
694
695                                 // play sound
696                                 m_playingSounds->push_back(sound);
697
698                                 alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
699                                 start();
700
701                                 alcProcessContext(m_context);
702                         }
703                 }
704         }
705         catch(AUD_Exception&)
706         {
707                 unlock();
708                 throw;
709         }
710
711         unlock();
712
713         if(sound)
714                 return sound;*/
715
716         return play(factory->createReader(), keep);
717 }
718
719 bool AUD_OpenALDevice::pause(AUD_Handle* handle)
720 {
721         bool result = false;
722
723         lock();
724
725         // only songs that are played can be paused
726         for(AUD_HandleIterator i = m_playingSounds->begin();
727                 i != m_playingSounds->end(); i++)
728         {
729                 if(*i == handle)
730                 {
731                         m_pausedSounds->push_back(*i);
732                         alSourcePause((*i)->source);
733                         m_playingSounds->erase(i);
734                         result = true;
735                         break;
736                 }
737         }
738
739         unlock();
740
741         return result;
742 }
743
744 bool AUD_OpenALDevice::resume(AUD_Handle* handle)
745 {
746         bool result = false;
747
748         lock();
749
750         // only songs that are paused can be resumed
751         for(AUD_HandleIterator i = m_pausedSounds->begin();
752                 i != m_pausedSounds->end(); i++)
753         {
754                 if(*i == handle)
755                 {
756                         m_playingSounds->push_back(*i);
757                         start();
758                         m_pausedSounds->erase(i);
759                         result = true;
760                         break;
761                 }
762         }
763
764         unlock();
765
766         return result;
767 }
768
769 bool AUD_OpenALDevice::stop(AUD_Handle* handle)
770 {
771         AUD_OpenALHandle* sound;
772
773         bool result = false;
774
775         lock();
776
777         for(AUD_HandleIterator i = m_playingSounds->begin();
778                 i != m_playingSounds->end(); i++)
779         {
780                 if(*i == handle)
781                 {
782                         sound = *i;
783                         alDeleteSources(1, &sound->source);
784                         if(!sound->isBuffered)
785                         {
786                                 alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
787                         }
788                         delete *i;
789                         m_playingSounds->erase(i);
790                         result = true;
791                         break;
792                 }
793         }
794         if(!result)
795         {
796                 for(AUD_HandleIterator i = m_pausedSounds->begin();
797                         i != m_pausedSounds->end(); i++)
798                 {
799                         if(*i == handle)
800                         {
801                                 sound = *i;
802                                 alDeleteSources(1, &sound->source);
803                                 if(!sound->isBuffered)
804                                 {
805                                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
806                                 }
807                                 delete *i;
808                                 m_pausedSounds->erase(i);
809                                 result = true;
810                                 break;
811                         }
812                 }
813         }
814
815         unlock();
816
817         return result;
818 }
819
820 bool AUD_OpenALDevice::getKeep(AUD_Handle* handle)
821 {
822         bool result = false;
823
824         lock();
825
826         if(isValid(handle))
827                 result = ((AUD_OpenALHandle*)handle)->keep;
828
829         unlock();
830
831         return result;
832 }
833
834 bool AUD_OpenALDevice::setKeep(AUD_Handle* handle, bool keep)
835 {
836         bool result = false;
837
838         lock();
839
840         if(isValid(handle))
841         {
842                 ((AUD_OpenALHandle*)handle)->keep = keep;
843                 result = true;
844         }
845
846         unlock();
847
848         return result;
849 }
850
851 bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position)
852 {
853         bool result = false;
854
855         lock();
856
857         if(isValid(handle))
858         {
859                 AUD_OpenALHandle* alhandle = (AUD_OpenALHandle*)handle;
860                 if(alhandle->isBuffered)
861                         alSourcef(alhandle->source, AL_SEC_OFFSET, position);
862                 else
863                 {
864                         alhandle->reader->seek((int)(position *
865                                                                                  alhandle->reader->getSpecs().rate));
866                         alhandle->eos = false;
867
868                         ALint info;
869
870                         alGetSourcei(alhandle->source, AL_SOURCE_STATE, &info);
871
872                         if(info != AL_PLAYING)
873                         {
874                                 if(info == AL_PAUSED)
875                                         alSourceStop(alhandle->source);
876
877                                 alSourcei(alhandle->source, AL_BUFFER, 0);
878                                 alhandle->current = 0;
879
880                                 ALenum err;
881                                 if((err = alGetError()) == AL_NO_ERROR)
882                                 {
883                                         int length;
884                                         AUD_DeviceSpecs specs = m_specs;
885                                         specs.specs = alhandle->reader->getSpecs();
886                                         m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
887
888                                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
889                                         {
890                                                 length = m_buffersize;
891                                                 alhandle->reader->read(length, alhandle->eos, m_buffer.getBuffer());
892                                                 alBufferData(alhandle->buffers[i], alhandle->format,
893                                                                          m_buffer.getBuffer(),
894                                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
895                                                                          specs.rate);
896
897                                                 if(alGetError() != AL_NO_ERROR)
898                                                         break;
899                                         }
900
901                                         if(alhandle->loopcount != 0)
902                                                 alhandle->eos = false;
903
904                                         alSourceQueueBuffers(alhandle->source,
905                                                                                  AUD_OPENAL_CYCLE_BUFFERS,
906                                                                                  alhandle->buffers);
907                                 }
908
909                                 alSourceRewind(alhandle->source);
910                         }
911                 }
912                 result = true;
913         }
914
915         unlock();
916         return result;
917 }
918
919 float AUD_OpenALDevice::getPosition(AUD_Handle* handle)
920 {
921         float position = 0.0f;
922
923         lock();
924
925         if(isValid(handle))
926         {
927                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
928                 alGetSourcef(h->source, AL_SEC_OFFSET, &position);
929                 if(!h->isBuffered)
930                 {
931                         AUD_Specs specs = h->reader->getSpecs();
932                         position += (h->reader->getPosition() - m_buffersize *
933                                                                         AUD_OPENAL_CYCLE_BUFFERS) /
934                                            (float)specs.rate;
935                 }
936         }
937
938         unlock();
939         return position;
940 }
941
942 AUD_Status AUD_OpenALDevice::getStatus(AUD_Handle* handle)
943 {
944         AUD_Status status = AUD_STATUS_INVALID;
945
946         lock();
947
948         for(AUD_HandleIterator i = m_playingSounds->begin();
949                 i != m_playingSounds->end(); i++)
950         {
951                 if(*i == handle)
952                 {
953                         status = AUD_STATUS_PLAYING;
954                         break;
955                 }
956         }
957         if(status == AUD_STATUS_INVALID)
958         {
959                 for(AUD_HandleIterator i = m_pausedSounds->begin();
960                         i != m_pausedSounds->end(); i++)
961                 {
962                         if(*i == handle)
963                         {
964                                 status = AUD_STATUS_PAUSED;
965                                 break;
966                         }
967                 }
968         }
969
970         unlock();
971
972         return status;
973 }
974
975 void AUD_OpenALDevice::lock()
976 {
977         pthread_mutex_lock(&m_mutex);
978 }
979
980 void AUD_OpenALDevice::unlock()
981 {
982         pthread_mutex_unlock(&m_mutex);
983 }
984
985 float AUD_OpenALDevice::getVolume() const
986 {
987         float result;
988         alGetListenerf(AL_GAIN, &result);
989         return result;
990 }
991
992 void AUD_OpenALDevice::setVolume(float volume)
993 {
994         alListenerf(AL_GAIN, volume);
995 }
996
997 float AUD_OpenALDevice::getVolume(AUD_Handle* handle)
998 {
999         lock();
1000         float result = std::numeric_limits<float>::quiet_NaN();
1001         if(isValid(handle))
1002                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_GAIN, &result);
1003         unlock();
1004         return result;
1005 }
1006
1007 bool AUD_OpenALDevice::setVolume(AUD_Handle* handle, float volume)
1008 {
1009         lock();
1010         bool result = isValid(handle);
1011         if(result)
1012                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_GAIN, volume);
1013         unlock();
1014         return result;
1015 }
1016
1017 float AUD_OpenALDevice::getPitch(AUD_Handle* handle)
1018 {
1019         lock();
1020         float result = std::numeric_limits<float>::quiet_NaN();
1021         if(isValid(handle))
1022                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_PITCH, &result);
1023         unlock();
1024         return result;
1025 }
1026
1027 bool AUD_OpenALDevice::setPitch(AUD_Handle* handle, float pitch)
1028 {
1029         lock();
1030         bool result = isValid(handle);
1031         if(result)
1032                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_PITCH, pitch);
1033         unlock();
1034         return result;
1035 }
1036
1037 int AUD_OpenALDevice::getLoopCount(AUD_Handle* handle)
1038 {
1039         lock();
1040         int result = 0;
1041         if(isValid(handle))
1042                 result = ((AUD_OpenALHandle*)handle)->loopcount;
1043         unlock();
1044         return result;
1045 }
1046
1047 bool AUD_OpenALDevice::setLoopCount(AUD_Handle* handle, int count)
1048 {
1049         lock();
1050         bool result = isValid(handle);
1051         if(result)
1052         {
1053                 ((AUD_OpenALHandle*)handle)->loopcount = count;
1054                 ((AUD_OpenALHandle*)handle)->eos = false;
1055         }
1056         unlock();
1057         return result;
1058 }
1059
1060 bool AUD_OpenALDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data)
1061 {
1062         lock();
1063         bool result = isValid(handle);
1064         if(result)
1065         {
1066                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
1067                 h->stop = callback;
1068                 h->stop_data = data;
1069         }
1070         unlock();
1071         return result;
1072 }
1073
1074 /* AUD_XXX Temorary disabled
1075
1076 bool AUD_OpenALDevice::bufferFactory(void *value)
1077 {
1078         bool result = false;
1079         AUD_IFactory* factory = (AUD_IFactory*) value;
1080
1081         // load the factory into an OpenAL buffer
1082         if(factory)
1083         {
1084                 // check if the factory is already buffered
1085                 lock();
1086                 for(AUD_BFIterator i = m_bufferedFactories->begin();
1087                         i != m_bufferedFactories->end(); i++)
1088                 {
1089                         if((*i)->factory == factory)
1090                         {
1091                                 result = true;
1092                                 break;
1093                         }
1094                 }
1095                 unlock();
1096                 if(result)
1097                         return result;
1098
1099                 AUD_IReader* reader = factory->createReader();
1100
1101                 if(reader == NULL)
1102                         return false;
1103
1104                 AUD_DeviceSpecs specs = m_specs;
1105                 specs.specs = reader->getSpecs();
1106
1107                 if(m_specs.format != AUD_FORMAT_FLOAT32)
1108                         reader = new AUD_ConverterReader(reader, m_specs);
1109
1110                 ALenum format;
1111
1112                 if(!getFormat(format, specs.specs))
1113                 {
1114                         return false;
1115                 }
1116
1117                 // load into a buffer
1118                 lock();
1119                 alcSuspendContext(m_context);
1120
1121                 AUD_OpenALBufferedFactory* bf = new AUD_OpenALBufferedFactory;
1122                 bf->factory = factory;
1123
1124                 try
1125                 {
1126                         alGenBuffers(1, &bf->buffer);
1127                         if(alGetError() != AL_NO_ERROR)
1128                                 AUD_THROW(AUD_ERROR_OPENAL);
1129
1130                         try
1131                         {
1132                                 sample_t* buf;
1133                                 int length = reader->getLength();
1134
1135                                 reader->read(length, buf);
1136                                 alBufferData(bf->buffer, format, buf,
1137                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
1138                                                          specs.rate);
1139                                 if(alGetError() != AL_NO_ERROR)
1140                                         AUD_THROW(AUD_ERROR_OPENAL);
1141                         }
1142                         catch(AUD_Exception&)
1143                         {
1144                                 alDeleteBuffers(1, &bf->buffer);
1145                                 throw;
1146                         }
1147                 }
1148                 catch(AUD_Exception&)
1149                 {
1150                         delete bf;
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 }