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