18c50d292258cd1930bf22c354a02a7379396e9c
[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 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
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->data_end)
170                                                         {
171                                                                 // read data
172                                                                 length = m_buffersize;
173                                                                 sound->reader->read(length, 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, m_buffer.getBuffer());
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                                                                                          m_buffer.getBuffer(), 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                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
386                 }
387                 delete sound;
388                 m_playingSounds->erase(m_playingSounds->begin());
389         }
390
391         // delete all paused sounds
392         while(!m_pausedSounds->empty())
393         {
394                 sound = *(m_pausedSounds->begin());
395                 alDeleteSources(1, &sound->source);
396                 if(!sound->isBuffered)
397                 {
398                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
399                 }
400                 delete sound;
401                 m_pausedSounds->erase(m_pausedSounds->begin());
402         }
403
404         // delete all buffered factories
405         while(!m_bufferedFactories->empty())
406         {
407                 alDeleteBuffers(1, &(*(m_bufferedFactories->begin()))->buffer);
408                 delete *m_bufferedFactories->begin();
409                 m_bufferedFactories->erase(m_bufferedFactories->begin());
410         }
411
412         alcProcessContext(m_context);
413
414         // wait for the thread to stop
415         if(m_playing)
416         {
417                 unlock();
418                 pthread_join(m_thread, NULL);
419         }
420         else
421                 unlock();
422
423         delete m_playingSounds;
424         delete m_pausedSounds;
425         delete m_bufferedFactories;
426
427         // quit OpenAL
428         alcMakeContextCurrent(NULL);
429         alcDestroyContext(m_context);
430         alcCloseDevice(m_device);
431
432         pthread_mutex_destroy(&m_mutex);
433 }
434
435 AUD_DeviceSpecs AUD_OpenALDevice::getSpecs() const
436 {
437         return m_specs;
438 }
439
440 bool AUD_OpenALDevice::getFormat(ALenum &format, AUD_Specs specs)
441 {
442         bool valid = true;
443         format = 0;
444
445         switch(m_specs.format)
446         {
447         case AUD_FORMAT_S16:
448                 switch(specs.channels)
449                 {
450                 case AUD_CHANNELS_MONO:
451                         format = AL_FORMAT_MONO16;
452                         break;
453                 case AUD_CHANNELS_STEREO:
454                         format = AL_FORMAT_STEREO16;
455                         break;
456                 case AUD_CHANNELS_SURROUND4:
457                         if(m_useMC)
458                         {
459                                 format = alGetEnumValue("AL_FORMAT_QUAD16");
460                                 break;
461                         }
462                 case AUD_CHANNELS_SURROUND51:
463                         if(m_useMC)
464                         {
465                                 format = alGetEnumValue("AL_FORMAT_51CHN16");
466                                 break;
467                         }
468                 case AUD_CHANNELS_SURROUND61:
469                         if(m_useMC)
470                         {
471                                 format = alGetEnumValue("AL_FORMAT_61CHN16");
472                                 break;
473                         }
474                 case AUD_CHANNELS_SURROUND71:
475                         if(m_useMC)
476                         {
477                                 format = alGetEnumValue("AL_FORMAT_71CHN16");
478                                 break;
479                         }
480                 default:
481                         valid = false;
482                 }
483                 break;
484         case AUD_FORMAT_FLOAT32:
485                 switch(specs.channels)
486                 {
487                 case AUD_CHANNELS_MONO:
488                         format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
489                         break;
490                 case AUD_CHANNELS_STEREO:
491                         format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
492                         break;
493                 case AUD_CHANNELS_SURROUND4:
494                         if(m_useMC)
495                         {
496                                 format = alGetEnumValue("AL_FORMAT_QUAD32");
497                                 break;
498                         }
499                 case AUD_CHANNELS_SURROUND51:
500                         if(m_useMC)
501                         {
502                                 format = alGetEnumValue("AL_FORMAT_51CHN32");
503                                 break;
504                         }
505                 case AUD_CHANNELS_SURROUND61:
506                         if(m_useMC)
507                         {
508                                 format = alGetEnumValue("AL_FORMAT_61CHN32");
509                                 break;
510                         }
511                 case AUD_CHANNELS_SURROUND71:
512                         if(m_useMC)
513                         {
514                                 format = alGetEnumValue("AL_FORMAT_71CHN32");
515                                 break;
516                         }
517                 default:
518                         valid = false;
519                 }
520                 break;
521         default:
522                 valid = false;
523         }
524
525         if(!format)
526                 valid = false;
527
528         return valid;
529 }
530
531 static const char* genbuffer_error = "AUD_OpenALDevice: Buffer couldn't be "
532                                                                          "generated.";
533 static const char* gensource_error = "AUD_OpenALDevice: Source couldn't be "
534                                                                          "generated.";
535 static const char* queue_error = "AUD_OpenALDevice: Buffer couldn't be "
536                                                                  "queued to the source.";
537 static const char* bufferdata_error = "AUD_OpenALDevice: Buffer couldn't be "
538                                                                           "filled with data.";
539
540 AUD_Handle* AUD_OpenALDevice::play(AUD_Reference<AUD_IReader> reader, bool keep)
541 {
542         AUD_OpenALHandle* sound = NULL;
543
544         AUD_DeviceSpecs specs = m_specs;
545         specs.specs = reader->getSpecs();
546
547         // check format
548         bool valid = specs.channels != AUD_CHANNELS_INVALID;
549
550         if(m_specs.format != AUD_FORMAT_FLOAT32)
551                 reader = new AUD_ConverterReader(reader, m_specs);
552
553         // create the handle
554         sound = new AUD_OpenALHandle;
555         sound->keep = keep;
556         sound->reader = reader;
557         sound->current = 0;
558         sound->isBuffered = false;
559         sound->data_end = false;
560         sound->loopcount = 0;
561         sound->stop = NULL;
562         sound->stop_data = NULL;
563
564         valid &= getFormat(sound->format, specs.specs);
565
566         if(!valid)
567         {
568                 delete sound;
569                 return NULL;
570         }
571
572         lock();
573         alcSuspendContext(m_context);
574
575         // OpenAL playback code
576         try
577         {
578                 alGenBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
579                 if(alGetError() != AL_NO_ERROR)
580                         AUD_THROW(AUD_ERROR_OPENAL, genbuffer_error);
581
582                 try
583                 {
584                         m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
585                         int length;
586
587                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
588                         {
589                                 length = m_buffersize;
590                                 reader->read(length, m_buffer.getBuffer());
591                                 alBufferData(sound->buffers[i], sound->format, m_buffer.getBuffer(),
592                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
593                                                          specs.rate);
594                                 if(alGetError() != AL_NO_ERROR)
595                                         AUD_THROW(AUD_ERROR_OPENAL, bufferdata_error);
596                         }
597
598                         alGenSources(1, &sound->source);
599                         if(alGetError() != AL_NO_ERROR)
600                                 AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
601
602                         try
603                         {
604                                 alSourceQueueBuffers(sound->source, AUD_OPENAL_CYCLE_BUFFERS,
605                                                                          sound->buffers);
606                                 if(alGetError() != AL_NO_ERROR)
607                                         AUD_THROW(AUD_ERROR_OPENAL, queue_error);
608                         }
609                         catch(AUD_Exception&)
610                         {
611                                 alDeleteSources(1, &sound->source);
612                                 throw;
613                         }
614                 }
615                 catch(AUD_Exception&)
616                 {
617                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
618                         throw;
619                 }
620         }
621         catch(AUD_Exception&)
622         {
623                 delete sound;
624                 alcProcessContext(m_context);
625                 unlock();
626                 throw;
627         }
628
629         // play sound
630         m_playingSounds->push_back(sound);
631         alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
632
633         start();
634
635         alcProcessContext(m_context);
636         unlock();
637
638         return sound;
639 }
640
641 AUD_Handle* AUD_OpenALDevice::play(AUD_Reference<AUD_IFactory> factory, bool keep)
642 {
643         /* AUD_XXX disabled
644         AUD_OpenALHandle* sound = NULL;
645
646         lock();
647
648         try
649         {
650                 // check if it is a buffered factory
651                 for(AUD_BFIterator i = m_bufferedFactories->begin();
652                         i != m_bufferedFactories->end(); i++)
653                 {
654                         if((*i)->factory == factory)
655                         {
656                                 // create the handle
657                                 sound = new AUD_OpenALHandle;
658                                 sound->keep = keep;
659                                 sound->current = -1;
660                                 sound->isBuffered = true;
661                                 sound->data_end = true;
662                                 sound->loopcount = 0;
663                                 sound->stop = NULL;
664                                 sound->stop_data = NULL;
665
666                                 alcSuspendContext(m_context);
667
668                                 // OpenAL playback code
669                                 try
670                                 {
671                                         alGenSources(1, &sound->source);
672                                         if(alGetError() != AL_NO_ERROR)
673                                                 AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
674
675                                         try
676                                         {
677                                                 alSourcei(sound->source, AL_BUFFER, (*i)->buffer);
678                                                 if(alGetError() != AL_NO_ERROR)
679                                                         AUD_THROW(AUD_ERROR_OPENAL, queue_error);
680                                         }
681                                         catch(AUD_Exception&)
682                                         {
683                                                 alDeleteSources(1, &sound->source);
684                                                 throw;
685                                         }
686                                 }
687                                 catch(AUD_Exception&)
688                                 {
689                                         delete sound;
690                                         alcProcessContext(m_context);
691                                         throw;
692                                 }
693
694                                 // play sound
695                                 m_playingSounds->push_back(sound);
696
697                                 alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
698                                 start();
699
700                                 alcProcessContext(m_context);
701                         }
702                 }
703         }
704         catch(AUD_Exception&)
705         {
706                 unlock();
707                 throw;
708         }
709
710         unlock();
711
712         if(sound)
713                 return sound;*/
714
715         return play(factory->createReader(), keep);
716 }
717
718 bool AUD_OpenALDevice::pause(AUD_Handle* handle)
719 {
720         bool result = false;
721
722         lock();
723
724         // only songs that are played can be paused
725         for(AUD_HandleIterator i = m_playingSounds->begin();
726                 i != m_playingSounds->end(); i++)
727         {
728                 if(*i == handle)
729                 {
730                         m_pausedSounds->push_back(*i);
731                         alSourcePause((*i)->source);
732                         m_playingSounds->erase(i);
733                         result = true;
734                         break;
735                 }
736         }
737
738         unlock();
739
740         return result;
741 }
742
743 bool AUD_OpenALDevice::resume(AUD_Handle* handle)
744 {
745         bool result = false;
746
747         lock();
748
749         // only songs that are paused can be resumed
750         for(AUD_HandleIterator i = m_pausedSounds->begin();
751                 i != m_pausedSounds->end(); i++)
752         {
753                 if(*i == handle)
754                 {
755                         m_playingSounds->push_back(*i);
756                         start();
757                         m_pausedSounds->erase(i);
758                         result = true;
759                         break;
760                 }
761         }
762
763         unlock();
764
765         return result;
766 }
767
768 bool AUD_OpenALDevice::stop(AUD_Handle* handle)
769 {
770         AUD_OpenALHandle* sound;
771
772         bool result = false;
773
774         lock();
775
776         for(AUD_HandleIterator i = m_playingSounds->begin();
777                 i != m_playingSounds->end(); i++)
778         {
779                 if(*i == handle)
780                 {
781                         sound = *i;
782                         alDeleteSources(1, &sound->source);
783                         if(!sound->isBuffered)
784                         {
785                                 alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
786                         }
787                         delete *i;
788                         m_playingSounds->erase(i);
789                         result = true;
790                         break;
791                 }
792         }
793         if(!result)
794         {
795                 for(AUD_HandleIterator i = m_pausedSounds->begin();
796                         i != m_pausedSounds->end(); i++)
797                 {
798                         if(*i == handle)
799                         {
800                                 sound = *i;
801                                 alDeleteSources(1, &sound->source);
802                                 if(!sound->isBuffered)
803                                 {
804                                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
805                                 }
806                                 delete *i;
807                                 m_pausedSounds->erase(i);
808                                 result = true;
809                                 break;
810                         }
811                 }
812         }
813
814         unlock();
815
816         return result;
817 }
818
819 bool AUD_OpenALDevice::getKeep(AUD_Handle* handle)
820 {
821         bool result = false;
822
823         lock();
824
825         if(isValid(handle))
826                 result = ((AUD_OpenALHandle*)handle)->keep;
827
828         unlock();
829
830         return result;
831 }
832
833 bool AUD_OpenALDevice::setKeep(AUD_Handle* handle, bool keep)
834 {
835         bool result = false;
836
837         lock();
838
839         if(isValid(handle))
840         {
841                 ((AUD_OpenALHandle*)handle)->keep = keep;
842                 result = true;
843         }
844
845         unlock();
846
847         return result;
848 }
849
850 bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position)
851 {
852         bool result = false;
853
854         lock();
855
856         if(isValid(handle))
857         {
858                 AUD_OpenALHandle* alhandle = (AUD_OpenALHandle*)handle;
859                 if(alhandle->isBuffered)
860                         alSourcef(alhandle->source, AL_SEC_OFFSET, position);
861                 else
862                 {
863                         alhandle->reader->seek((int)(position *
864                                                                                  alhandle->reader->getSpecs().rate));
865                         alhandle->data_end = false;
866
867                         ALint info;
868
869                         alGetSourcei(alhandle->source, AL_SOURCE_STATE, &info);
870
871                         if(info != AL_PLAYING)
872                         {
873                                 if(info == AL_PAUSED)
874                                         alSourceStop(alhandle->source);
875
876                                 alSourcei(alhandle->source, AL_BUFFER, 0);
877                                 alhandle->current = 0;
878
879                                 ALenum err;
880                                 if((err = alGetError()) == AL_NO_ERROR)
881                                 {
882                                         int length;
883                                         AUD_DeviceSpecs specs = m_specs;
884                                         specs.specs = alhandle->reader->getSpecs();
885                                         m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
886
887                                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
888                                         {
889                                                 length = m_buffersize;
890                                                 alhandle->reader->read(length, m_buffer.getBuffer());
891                                                 alBufferData(alhandle->buffers[i], alhandle->format,
892                                                                          m_buffer.getBuffer(),
893                                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
894                                                                          specs.rate);
895
896                                                 if(alGetError() != AL_NO_ERROR)
897                                                         break;
898                                         }
899
900                                         alSourceQueueBuffers(alhandle->source,
901                                                                                  AUD_OPENAL_CYCLE_BUFFERS,
902                                                                                  alhandle->buffers);
903                                 }
904
905                                 alSourceRewind(alhandle->source);
906                         }
907                 }
908                 result = true;
909         }
910
911         unlock();
912         return result;
913 }
914
915 float AUD_OpenALDevice::getPosition(AUD_Handle* handle)
916 {
917         float position = 0.0f;
918
919         lock();
920
921         if(isValid(handle))
922         {
923                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
924                 alGetSourcef(h->source, AL_SEC_OFFSET, &position);
925                 if(!h->isBuffered)
926                 {
927                         AUD_Specs specs = h->reader->getSpecs();
928                         position += (h->reader->getPosition() - m_buffersize *
929                                                                         AUD_OPENAL_CYCLE_BUFFERS) /
930                                            (float)specs.rate;
931                 }
932         }
933
934         unlock();
935         return position;
936 }
937
938 AUD_Status AUD_OpenALDevice::getStatus(AUD_Handle* handle)
939 {
940         AUD_Status status = AUD_STATUS_INVALID;
941
942         lock();
943
944         for(AUD_HandleIterator i = m_playingSounds->begin();
945                 i != m_playingSounds->end(); i++)
946         {
947                 if(*i == handle)
948                 {
949                         status = AUD_STATUS_PLAYING;
950                         break;
951                 }
952         }
953         if(status == AUD_STATUS_INVALID)
954         {
955                 for(AUD_HandleIterator i = m_pausedSounds->begin();
956                         i != m_pausedSounds->end(); i++)
957                 {
958                         if(*i == handle)
959                         {
960                                 status = AUD_STATUS_PAUSED;
961                                 break;
962                         }
963                 }
964         }
965
966         unlock();
967
968         return status;
969 }
970
971 void AUD_OpenALDevice::lock()
972 {
973         pthread_mutex_lock(&m_mutex);
974 }
975
976 void AUD_OpenALDevice::unlock()
977 {
978         pthread_mutex_unlock(&m_mutex);
979 }
980
981 float AUD_OpenALDevice::getVolume() const
982 {
983         float result;
984         alGetListenerf(AL_GAIN, &result);
985         return result;
986 }
987
988 void AUD_OpenALDevice::setVolume(float volume)
989 {
990         alListenerf(AL_GAIN, volume);
991 }
992
993 float AUD_OpenALDevice::getVolume(AUD_Handle* handle)
994 {
995         lock();
996         float result = std::numeric_limits<float>::quiet_NaN();
997         if(isValid(handle))
998                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_GAIN, &result);
999         unlock();
1000         return result;
1001 }
1002
1003 bool AUD_OpenALDevice::setVolume(AUD_Handle* handle, float volume)
1004 {
1005         lock();
1006         bool result = isValid(handle);
1007         if(result)
1008                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_GAIN, volume);
1009         unlock();
1010         return result;
1011 }
1012
1013 float AUD_OpenALDevice::getPitch(AUD_Handle* handle)
1014 {
1015         lock();
1016         float result = std::numeric_limits<float>::quiet_NaN();
1017         if(isValid(handle))
1018                 alGetSourcef(((AUD_OpenALHandle*)handle)->source,AL_PITCH, &result);
1019         unlock();
1020         return result;
1021 }
1022
1023 bool AUD_OpenALDevice::setPitch(AUD_Handle* handle, float pitch)
1024 {
1025         lock();
1026         bool result = isValid(handle);
1027         if(result)
1028                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_PITCH, pitch);
1029         unlock();
1030         return result;
1031 }
1032
1033 int AUD_OpenALDevice::getLoopCount(AUD_Handle* handle)
1034 {
1035         lock();
1036         int result = 0;
1037         if(isValid(handle))
1038                 result = ((AUD_OpenALHandle*)handle)->loopcount;
1039         unlock();
1040         return result;
1041 }
1042
1043 bool AUD_OpenALDevice::setLoopCount(AUD_Handle* handle, int count)
1044 {
1045         lock();
1046         bool result = isValid(handle);
1047         if(result)
1048                 ((AUD_OpenALHandle*)handle)->loopcount = count;
1049         unlock();
1050         return result;
1051 }
1052
1053 bool AUD_OpenALDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data)
1054 {
1055         lock();
1056         bool result = isValid(handle);
1057         if(result)
1058         {
1059                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
1060                 h->stop = callback;
1061                 h->stop_data = data;
1062         }
1063         unlock();
1064         return result;
1065 }
1066
1067 /* AUD_XXX Temorary disabled
1068
1069 bool AUD_OpenALDevice::bufferFactory(void *value)
1070 {
1071         bool result = false;
1072         AUD_IFactory* factory = (AUD_IFactory*) value;
1073
1074         // load the factory into an OpenAL buffer
1075         if(factory)
1076         {
1077                 // check if the factory is already buffered
1078                 lock();
1079                 for(AUD_BFIterator i = m_bufferedFactories->begin();
1080                         i != m_bufferedFactories->end(); i++)
1081                 {
1082                         if((*i)->factory == factory)
1083                         {
1084                                 result = true;
1085                                 break;
1086                         }
1087                 }
1088                 unlock();
1089                 if(result)
1090                         return result;
1091
1092                 AUD_IReader* reader = factory->createReader();
1093
1094                 if(reader == NULL)
1095                         return false;
1096
1097                 AUD_DeviceSpecs specs = m_specs;
1098                 specs.specs = reader->getSpecs();
1099
1100                 if(m_specs.format != AUD_FORMAT_FLOAT32)
1101                         reader = new AUD_ConverterReader(reader, m_specs);
1102
1103                 ALenum format;
1104
1105                 if(!getFormat(format, specs.specs))
1106                 {
1107                         return false;
1108                 }
1109
1110                 // load into a buffer
1111                 lock();
1112                 alcSuspendContext(m_context);
1113
1114                 AUD_OpenALBufferedFactory* bf = new AUD_OpenALBufferedFactory;
1115                 bf->factory = factory;
1116
1117                 try
1118                 {
1119                         alGenBuffers(1, &bf->buffer);
1120                         if(alGetError() != AL_NO_ERROR)
1121                                 AUD_THROW(AUD_ERROR_OPENAL);
1122
1123                         try
1124                         {
1125                                 sample_t* buf;
1126                                 int length = reader->getLength();
1127
1128                                 reader->read(length, buf);
1129                                 alBufferData(bf->buffer, format, buf,
1130                                                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
1131                                                          specs.rate);
1132                                 if(alGetError() != AL_NO_ERROR)
1133                                         AUD_THROW(AUD_ERROR_OPENAL);
1134                         }
1135                         catch(AUD_Exception&)
1136                         {
1137                                 alDeleteBuffers(1, &bf->buffer);
1138                                 throw;
1139                         }
1140                 }
1141                 catch(AUD_Exception&)
1142                 {
1143                         delete bf;
1144                         alcProcessContext(m_context);
1145                         unlock();
1146                         return false;
1147                 }
1148
1149                 m_bufferedFactories->push_back(bf);
1150
1151                 alcProcessContext(m_context);
1152                 unlock();
1153         }
1154         else
1155         {
1156                 // stop all playing and paused buffered sources
1157                 lock();
1158                 alcSuspendContext(m_context);
1159
1160                 AUD_OpenALHandle* sound;
1161                 AUD_HandleIterator it = m_playingSounds->begin();
1162                 while(it != m_playingSounds->end())
1163                 {
1164                         sound = *it;
1165                         ++it;
1166
1167                         if(sound->isBuffered)
1168                                 stop(sound);
1169                 }
1170                 alcProcessContext(m_context);
1171
1172                 while(!m_bufferedFactories->empty())
1173                 {
1174                         alDeleteBuffers(1,
1175                                                         &(*(m_bufferedFactories->begin()))->buffer);
1176                         delete *m_bufferedFactories->begin();
1177                         m_bufferedFactories->erase(m_bufferedFactories->begin());
1178                 }
1179                 unlock();
1180         }
1181
1182         return true;
1183 }*/
1184
1185 /******************************************************************************/
1186 /**************************** 3D Device Code **********************************/
1187 /******************************************************************************/
1188
1189 AUD_Vector3 AUD_OpenALDevice::getListenerLocation() const
1190 {
1191         ALfloat p[3];
1192         alGetListenerfv(AL_POSITION, p);
1193         return AUD_Vector3(p[0], p[1], p[2]);
1194 }
1195
1196 void AUD_OpenALDevice::setListenerLocation(const AUD_Vector3& location)
1197 {
1198         alListenerfv(AL_POSITION, (ALfloat*)location.get());
1199 }
1200
1201 AUD_Vector3 AUD_OpenALDevice::getListenerVelocity() const
1202 {
1203         ALfloat v[3];
1204         alGetListenerfv(AL_VELOCITY, v);
1205         return AUD_Vector3(v[0], v[1], v[2]);
1206 }
1207
1208 void AUD_OpenALDevice::setListenerVelocity(const AUD_Vector3& velocity)
1209 {
1210         alListenerfv(AL_VELOCITY, (ALfloat*)velocity.get());
1211 }
1212
1213 AUD_Quaternion AUD_OpenALDevice::getListenerOrientation() const
1214 {
1215         // AUD_XXX not implemented yet
1216         return AUD_Quaternion(0, 0, 0, 0);
1217 }
1218
1219 void AUD_OpenALDevice::setListenerOrientation(const AUD_Quaternion& orientation)
1220 {
1221         ALfloat direction[6];
1222         direction[0] = -2 * (orientation.w() * orientation.y() +
1223                                                  orientation.x() * orientation.z());
1224         direction[1] = 2 * (orientation.x() * orientation.w() -
1225                                                 orientation.z() * orientation.y());
1226         direction[2] = 2 * (orientation.x() * orientation.x() +
1227                                                 orientation.y() * orientation.y()) - 1;
1228         direction[3] = 2 * (orientation.x() * orientation.y() -
1229                                                 orientation.w() * orientation.z());
1230         direction[4] = 1 - 2 * (orientation.x() * orientation.x() +
1231                                                         orientation.z() * orientation.z());
1232         direction[5] = 2 * (orientation.w() * orientation.x() +
1233                                                 orientation.y() * orientation.z());
1234         alListenerfv(AL_ORIENTATION, direction);
1235 }
1236
1237 float AUD_OpenALDevice::getSpeedOfSound() const
1238 {
1239         return alGetFloat(AL_SPEED_OF_SOUND);
1240 }
1241
1242 void AUD_OpenALDevice::setSpeedOfSound(float speed)
1243 {
1244         alSpeedOfSound(speed);
1245 }
1246
1247 float AUD_OpenALDevice::getDopplerFactor() const
1248 {
1249         return alGetFloat(AL_DOPPLER_FACTOR);
1250 }
1251
1252 void AUD_OpenALDevice::setDopplerFactor(float factor)
1253 {
1254         alDopplerFactor(factor);
1255 }
1256
1257 AUD_DistanceModel AUD_OpenALDevice::getDistanceModel() const
1258 {
1259         switch(alGetInteger(AL_DISTANCE_MODEL))
1260         {
1261         case AL_INVERSE_DISTANCE:
1262                 return AUD_DISTANCE_MODEL_INVERSE;
1263         case AL_INVERSE_DISTANCE_CLAMPED:
1264                 return AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
1265         case AL_LINEAR_DISTANCE:
1266                 return AUD_DISTANCE_MODEL_LINEAR;
1267         case AL_LINEAR_DISTANCE_CLAMPED:
1268                 return AUD_DISTANCE_MODEL_LINEAR_CLAMPED;
1269         case AL_EXPONENT_DISTANCE:
1270                 return AUD_DISTANCE_MODEL_EXPONENT;
1271         case AL_EXPONENT_DISTANCE_CLAMPED:
1272                 return AUD_DISTANCE_MODEL_EXPONENT_CLAMPED;
1273         default:
1274                 return AUD_DISTANCE_MODEL_INVALID;
1275         }
1276 }
1277
1278 void AUD_OpenALDevice::setDistanceModel(AUD_DistanceModel model)
1279 {
1280         switch(model)
1281         {
1282         case AUD_DISTANCE_MODEL_INVERSE:
1283                 alDistanceModel(AL_INVERSE_DISTANCE);
1284                 break;
1285         case AUD_DISTANCE_MODEL_INVERSE_CLAMPED:
1286                 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
1287                 break;
1288         case AUD_DISTANCE_MODEL_LINEAR:
1289                 alDistanceModel(AL_LINEAR_DISTANCE);
1290                 break;
1291         case AUD_DISTANCE_MODEL_LINEAR_CLAMPED:
1292                 alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
1293                 break;
1294         case AUD_DISTANCE_MODEL_EXPONENT:
1295                 alDistanceModel(AL_EXPONENT_DISTANCE);
1296                 break;
1297         case AUD_DISTANCE_MODEL_EXPONENT_CLAMPED:
1298                 alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
1299                 break;
1300         default:
1301                 alDistanceModel(AL_NONE);
1302         }
1303 }
1304
1305 AUD_Vector3 AUD_OpenALDevice::getSourceLocation(AUD_Handle* handle)
1306 {
1307         AUD_Vector3 result = AUD_Vector3(0, 0, 0);
1308         ALfloat p[3];
1309         lock();
1310
1311         if(isValid(handle))
1312         {
1313                 alGetSourcefv(((AUD_OpenALHandle*)handle)->source, AL_POSITION, p);
1314                 result = AUD_Vector3(p[0], p[1], p[2]);
1315         }
1316
1317         unlock();
1318         return result;
1319 }
1320
1321 bool AUD_OpenALDevice::setSourceLocation(AUD_Handle* handle, const AUD_Vector3& location)
1322 {
1323         lock();
1324         bool result = isValid(handle);
1325
1326         if(result)
1327                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_POSITION,
1328                                    (ALfloat*)location.get());
1329
1330         unlock();
1331         return result;
1332 }
1333
1334 AUD_Vector3 AUD_OpenALDevice::getSourceVelocity(AUD_Handle* handle)
1335 {
1336         AUD_Vector3 result = AUD_Vector3(0, 0, 0);
1337         ALfloat v[3];
1338         lock();
1339
1340         if(isValid(handle))
1341         {
1342                 alGetSourcefv(((AUD_OpenALHandle*)handle)->source, AL_VELOCITY, v);
1343                 result = AUD_Vector3(v[0], v[1], v[2]);
1344         }
1345
1346         unlock();
1347         return result;
1348 }
1349
1350 bool AUD_OpenALDevice::setSourceVelocity(AUD_Handle* handle, const AUD_Vector3& velocity)
1351 {
1352         lock();
1353         bool result = isValid(handle);
1354
1355         if(result)
1356                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_VELOCITY,
1357                                    (ALfloat*)velocity.get());
1358
1359         unlock();
1360         return result;
1361 }
1362
1363 AUD_Quaternion AUD_OpenALDevice::getSourceOrientation(AUD_Handle* handle)
1364 {
1365         // AUD_XXX not implemented yet
1366         return AUD_Quaternion(0, 0, 0, 0);
1367 }
1368
1369 bool AUD_OpenALDevice::setSourceOrientation(AUD_Handle* handle, const AUD_Quaternion& orientation)
1370 {
1371         lock();
1372         bool result = isValid(handle);
1373
1374         if(result)
1375         {
1376                 ALfloat direction[3];
1377                 direction[0] = -2 * (orientation.w() * orientation.y() +
1378                                                          orientation.x() * orientation.z());
1379                 direction[1] = 2 * (orientation.x() * orientation.w() -
1380                                                         orientation.z() * orientation.y());
1381                 direction[2] = 2 * (orientation.x() * orientation.x() +
1382                                                         orientation.y() * orientation.y()) - 1;
1383                 alSourcefv(((AUD_OpenALHandle*)handle)->source, AL_DIRECTION,
1384                                    direction);
1385         }
1386
1387         unlock();
1388         return result;
1389 }
1390
1391 bool AUD_OpenALDevice::isRelative(AUD_Handle* handle)
1392 {
1393         int result = std::numeric_limits<float>::quiet_NaN();;
1394
1395         lock();
1396
1397         if(isValid(handle))
1398                 alGetSourcei(((AUD_OpenALHandle*)handle)->source, AL_SOURCE_RELATIVE,
1399                                          &result);
1400
1401         unlock();
1402         return result;
1403 }
1404
1405 bool AUD_OpenALDevice::setRelative(AUD_Handle* handle, bool relative)
1406 {
1407         lock();
1408         bool result = isValid(handle);
1409
1410         if(result)
1411                 alSourcei(((AUD_OpenALHandle*)handle)->source, AL_SOURCE_RELATIVE,
1412                                   relative);
1413
1414         unlock();
1415         return result;
1416 }
1417
1418 float AUD_OpenALDevice::getVolumeMaximum(AUD_Handle* handle)
1419 {
1420         float result = std::numeric_limits<float>::quiet_NaN();;
1421
1422         lock();
1423
1424         if(isValid(handle))
1425                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_GAIN,
1426                                          &result);
1427
1428         unlock();
1429         return result;
1430 }
1431
1432 bool AUD_OpenALDevice::setVolumeMaximum(AUD_Handle* handle, float volume)
1433 {
1434         lock();
1435         bool result = isValid(handle);
1436
1437         if(result)
1438
1439                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_GAIN,
1440                                   volume);
1441
1442         unlock();
1443         return result;
1444 }
1445
1446 float AUD_OpenALDevice::getVolumeMinimum(AUD_Handle* handle)
1447 {
1448         float result = std::numeric_limits<float>::quiet_NaN();;
1449
1450         lock();
1451
1452         if(isValid(handle))
1453                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MIN_GAIN,
1454                                          &result);
1455
1456         unlock();
1457         return result;
1458 }
1459
1460 bool AUD_OpenALDevice::setVolumeMinimum(AUD_Handle* handle, float volume)
1461 {
1462         lock();
1463         bool result = isValid(handle);
1464
1465         if(result)
1466                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MIN_GAIN,
1467                                   volume);
1468
1469         unlock();
1470         return result;
1471 }
1472
1473 float AUD_OpenALDevice::getDistanceMaximum(AUD_Handle* handle)
1474 {
1475         float result = std::numeric_limits<float>::quiet_NaN();;
1476
1477         lock();
1478
1479         if(isValid(handle))
1480                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_DISTANCE,
1481                                          &result);
1482
1483         unlock();
1484         return result;
1485 }
1486
1487 bool AUD_OpenALDevice::setDistanceMaximum(AUD_Handle* handle, float distance)
1488 {
1489         lock();
1490         bool result = isValid(handle);
1491
1492         if(result)
1493                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_MAX_DISTANCE,
1494                                   distance);
1495
1496         unlock();
1497         return result;
1498 }
1499
1500 float AUD_OpenALDevice::getDistanceReference(AUD_Handle* handle)
1501 {
1502         float result = std::numeric_limits<float>::quiet_NaN();;
1503
1504         lock();
1505
1506         if(isValid(handle))
1507                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_REFERENCE_DISTANCE,
1508                                          &result);
1509
1510         unlock();
1511         return result;
1512 }
1513
1514 bool AUD_OpenALDevice::setDistanceReference(AUD_Handle* handle, float distance)
1515 {
1516         lock();
1517         bool result = isValid(handle);
1518
1519         if(result)
1520                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_REFERENCE_DISTANCE,
1521                                   distance);
1522
1523         unlock();
1524         return result;
1525 }
1526
1527 float AUD_OpenALDevice::getAttenuation(AUD_Handle* handle)
1528 {
1529         float result = std::numeric_limits<float>::quiet_NaN();;
1530
1531         lock();
1532
1533         if(isValid(handle))
1534                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_ROLLOFF_FACTOR,
1535                                          &result);
1536
1537         unlock();
1538         return result;
1539 }
1540
1541 bool AUD_OpenALDevice::setAttenuation(AUD_Handle* handle, float factor)
1542 {
1543         lock();
1544         bool result = isValid(handle);
1545
1546         if(result)
1547                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_ROLLOFF_FACTOR,
1548                                   factor);
1549
1550         unlock();
1551         return result;
1552 }
1553
1554 float AUD_OpenALDevice::getConeAngleOuter(AUD_Handle* handle)
1555 {
1556         float result = std::numeric_limits<float>::quiet_NaN();;
1557
1558         lock();
1559
1560         if(isValid(handle))
1561                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_ANGLE,
1562                                          &result);
1563
1564         unlock();
1565         return result;
1566 }
1567
1568 bool AUD_OpenALDevice::setConeAngleOuter(AUD_Handle* handle, float angle)
1569 {
1570         lock();
1571         bool result = isValid(handle);
1572
1573         if(result)
1574                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_ANGLE,
1575                                   angle);
1576
1577         unlock();
1578         return result;
1579 }
1580
1581 float AUD_OpenALDevice::getConeAngleInner(AUD_Handle* handle)
1582 {
1583         float result = std::numeric_limits<float>::quiet_NaN();;
1584
1585         lock();
1586
1587         if(isValid(handle))
1588                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_INNER_ANGLE,
1589                                          &result);
1590
1591         unlock();
1592         return result;
1593 }
1594
1595 bool AUD_OpenALDevice::setConeAngleInner(AUD_Handle* handle, float angle)
1596 {
1597         lock();
1598         bool result = isValid(handle);
1599
1600         if(result)
1601                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_INNER_ANGLE,
1602                                   angle);
1603
1604         unlock();
1605         return result;
1606 }
1607
1608 float AUD_OpenALDevice::getConeVolumeOuter(AUD_Handle* handle)
1609 {
1610         float result = std::numeric_limits<float>::quiet_NaN();;
1611
1612         lock();
1613
1614         if(isValid(handle))
1615                 alGetSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_GAIN,
1616                                          &result);
1617
1618         unlock();
1619         return result;
1620 }
1621
1622 bool AUD_OpenALDevice::setConeVolumeOuter(AUD_Handle* handle, float volume)
1623 {
1624         lock();
1625         bool result = isValid(handle);
1626
1627         if(result)
1628                 alSourcef(((AUD_OpenALHandle*)handle)->source, AL_CONE_OUTER_GAIN,
1629                                   volume);
1630
1631         unlock();
1632         return result;
1633 }