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