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