soc-2008-mxcurioni: merged changes to revision 23516
[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_IMixer.h"
29 #include "AUD_ConverterFactory.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_Specs 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 = 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,
181                                                                                          length * AUD_SAMPLE_SIZE(specs),
182                                                                                          specs.rate);
183
184                                                                 if(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_Specs 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         m_device = alcOpenDevice(NULL);
275
276         if(!m_device)
277                 AUD_THROW(AUD_ERROR_OPENAL);
278
279         // at least try to set the frequency
280         ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
281         ALCint* attributes = attribs;
282         if(specs.rate == AUD_RATE_INVALID)
283                 attributes = NULL;
284
285         m_context = alcCreateContext(m_device, attributes);
286         alcMakeContextCurrent(m_context);
287
288         alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);
289
290         // check for specific formats and channel counts to be played back
291         if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
292                 specs.format = AUD_FORMAT_FLOAT32;
293
294         m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;
295
296         alGetError();
297
298         m_converter = new AUD_ConverterFactory(specs); AUD_NEW("factory")
299
300         m_specs = specs;
301         m_buffersize = buffersize;
302         m_playing = false;
303
304         m_playingSounds = new std::list<AUD_OpenALHandle*>(); AUD_NEW("list")
305         m_pausedSounds = new std::list<AUD_OpenALHandle*>(); AUD_NEW("list")
306         m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();
307         AUD_NEW("list")
308
309         pthread_mutexattr_t attr;
310         pthread_mutexattr_init(&attr);
311         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
312
313         pthread_mutex_init(&m_mutex, &attr);
314
315         pthread_mutexattr_destroy(&attr);
316 }
317
318 AUD_OpenALDevice::~AUD_OpenALDevice()
319 {
320         AUD_OpenALHandle* sound;
321
322         lock();
323         alcSuspendContext(m_context);
324
325         // delete all playing sounds
326         while(!m_playingSounds->empty())
327         {
328                 sound = *(m_playingSounds->begin());
329                 alDeleteSources(1, &sound->source);
330                 if(!sound->isBuffered)
331                 {
332                         delete sound->reader; AUD_DELETE("reader")
333                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
334                 }
335                 delete sound; AUD_DELETE("handle")
336                 m_playingSounds->erase(m_playingSounds->begin());
337         }
338
339         // delete all paused sounds
340         while(!m_pausedSounds->empty())
341         {
342                 sound = *(m_pausedSounds->begin());
343                 alDeleteSources(1, &sound->source);
344                 if(!sound->isBuffered)
345                 {
346                         delete sound->reader; AUD_DELETE("reader")
347                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
348                 }
349                 delete sound; AUD_DELETE("handle")
350                 m_pausedSounds->erase(m_pausedSounds->begin());
351         }
352
353         // delete all buffered factories
354         while(!m_bufferedFactories->empty())
355         {
356                 alDeleteBuffers(1, &(*(m_bufferedFactories->begin()))->buffer);
357                 delete *m_bufferedFactories->begin(); AUD_DELETE("bufferedfactory");
358                 m_bufferedFactories->erase(m_bufferedFactories->begin());
359         }
360
361         alcProcessContext(m_context);
362
363         // wait for the thread to stop
364         if(m_playing)
365         {
366                 unlock();
367                 pthread_join(m_thread, NULL);
368         }
369         else
370                 unlock();
371
372         delete m_playingSounds; AUD_DELETE("list")
373         delete m_pausedSounds; AUD_DELETE("list")
374         delete m_bufferedFactories; AUD_DELETE("list")
375
376         // quit OpenAL
377         alcMakeContextCurrent(NULL);
378         alcDestroyContext(m_context);
379         alcCloseDevice(m_device);
380
381         delete m_converter; AUD_DELETE("factory")
382
383         pthread_mutex_destroy(&m_mutex);
384 }
385
386 AUD_Specs AUD_OpenALDevice::getSpecs()
387 {
388         return m_specs;
389 }
390
391 bool AUD_OpenALDevice::getFormat(ALenum &format, AUD_Specs specs)
392 {
393         bool valid = true;
394         format = 0;
395
396         switch(specs.format)
397         {
398         case AUD_FORMAT_U8:
399                 switch(specs.channels)
400                 {
401                 case AUD_CHANNELS_MONO:
402                         format = AL_FORMAT_MONO8;
403                         break;
404                 case AUD_CHANNELS_STEREO:
405                         format = AL_FORMAT_STEREO8;
406                         break;
407                 case AUD_CHANNELS_SURROUND4:
408                         if(m_useMC)
409                         {
410                                 format = alGetEnumValue("AL_FORMAT_QUAD8");
411                                 break;
412                         }
413                 case AUD_CHANNELS_SURROUND51:
414                         if(m_useMC)
415                         {
416                                 format = alGetEnumValue("AL_FORMAT_51CHN8");
417                                 break;
418                         }
419                 case AUD_CHANNELS_SURROUND61:
420                         if(m_useMC)
421                         {
422                                 format = alGetEnumValue("AL_FORMAT_61CHN8");
423                                 break;
424                         }
425                 case AUD_CHANNELS_SURROUND71:
426                         if(m_useMC)
427                         {
428                                 format = alGetEnumValue("AL_FORMAT_71CHN8");
429                                 break;
430                         }
431                 default:
432                         valid = false;
433                 }
434                 break;
435         case AUD_FORMAT_S16:
436                 switch(specs.channels)
437                 {
438                 case AUD_CHANNELS_MONO:
439                         format = AL_FORMAT_MONO16;
440                         break;
441                 case AUD_CHANNELS_STEREO:
442                         format = AL_FORMAT_STEREO16;
443                         break;
444                 case AUD_CHANNELS_SURROUND4:
445                         if(m_useMC)
446                         {
447                                 format = alGetEnumValue("AL_FORMAT_QUAD16");
448                                 break;
449                         }
450                 case AUD_CHANNELS_SURROUND51:
451                         if(m_useMC)
452                         {
453                                 format = alGetEnumValue("AL_FORMAT_51CHN16");
454                                 break;
455                         }
456                 case AUD_CHANNELS_SURROUND61:
457                         if(m_useMC)
458                         {
459                                 format = alGetEnumValue("AL_FORMAT_61CHN16");
460                                 break;
461                         }
462                 case AUD_CHANNELS_SURROUND71:
463                         if(m_useMC)
464                         {
465                                 format = alGetEnumValue("AL_FORMAT_71CHN16");
466                                 break;
467                         }
468                 default:
469                         valid = false;
470                 }
471                 break;
472         case AUD_FORMAT_FLOAT32:
473                 switch(specs.channels)
474                 {
475                 case AUD_CHANNELS_MONO:
476                         format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
477                         break;
478                 case AUD_CHANNELS_STEREO:
479                         format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
480                         break;
481                 case AUD_CHANNELS_SURROUND4:
482                         if(m_useMC)
483                         {
484                                 format = alGetEnumValue("AL_FORMAT_QUAD32");
485                                 break;
486                         }
487                 case AUD_CHANNELS_SURROUND51:
488                         if(m_useMC)
489                         {
490                                 format = alGetEnumValue("AL_FORMAT_51CHN32");
491                                 break;
492                         }
493                 case AUD_CHANNELS_SURROUND61:
494                         if(m_useMC)
495                         {
496                                 format = alGetEnumValue("AL_FORMAT_61CHN32");
497                                 break;
498                         }
499                 case AUD_CHANNELS_SURROUND71:
500                         if(m_useMC)
501                         {
502                                 format = alGetEnumValue("AL_FORMAT_71CHN32");
503                                 break;
504                         }
505                 default:
506                         valid = false;
507                 }
508                 break;
509         default:
510                 valid = false;
511         }
512
513         if(!format)
514                 valid = false;
515
516         return valid;
517 }
518
519 AUD_Handle* AUD_OpenALDevice::play(AUD_IFactory* factory, bool keep)
520 {
521         lock();
522
523         AUD_OpenALHandle* sound = NULL;
524
525         try
526         {
527                 // check if it is a buffered factory
528                 for(AUD_BFIterator i = m_bufferedFactories->begin();
529                         i != m_bufferedFactories->end(); i++)
530                 {
531                         if((*i)->factory == factory)
532                         {
533                                 // create the handle
534                                 sound = new AUD_OpenALHandle; AUD_NEW("handle")
535                                 sound->keep = keep;
536                                 sound->current = -1;
537                                 sound->isBuffered = true;
538                                 sound->data_end = true;
539
540                                 alcSuspendContext(m_context);
541
542                                 // OpenAL playback code
543                                 try
544                                 {
545                                         alGenSources(1, &sound->source);
546                                         if(alGetError() != AL_NO_ERROR)
547                                                 AUD_THROW(AUD_ERROR_OPENAL);
548
549                                         try
550                                         {
551                                                 alSourcei(sound->source, AL_BUFFER, (*i)->buffer);
552                                                 if(alGetError() != AL_NO_ERROR)
553                                                         AUD_THROW(AUD_ERROR_OPENAL);
554                                         }
555                                         catch(AUD_Exception)
556                                         {
557                                                 alDeleteSources(1, &sound->source);
558                                                 throw;
559                                         }
560                                 }
561                                 catch(AUD_Exception)
562                                 {
563                                         delete sound; AUD_DELETE("handle")
564                                         alcProcessContext(m_context);
565                                         throw;
566                                 }
567
568                                 // play sound
569                                 m_playingSounds->push_back(sound);
570
571                                 alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
572                                 start();
573
574                                 alcProcessContext(m_context);
575                         }
576                 }
577         }
578         catch(AUD_Exception)
579         {
580                 unlock();
581                 throw;
582         }
583
584         unlock();
585
586         if(sound)
587                 return sound;
588
589         AUD_IReader* reader = factory->createReader();
590
591         if(reader == NULL)
592                 AUD_THROW(AUD_ERROR_READER);
593
594         AUD_Specs specs;
595
596         specs = reader->getSpecs();
597
598         // check format
599         bool valid = true;
600
601         if(specs.format == AUD_FORMAT_INVALID)
602                 valid = false;
603         else if(specs.format == AUD_FORMAT_S24 ||
604                         specs.format == AUD_FORMAT_S32 ||
605                         specs.format == AUD_FORMAT_FLOAT32 ||
606                         specs.format == AUD_FORMAT_FLOAT64)
607         {
608                 m_converter->setReader(reader);
609                 reader = m_converter->createReader();
610                 specs = reader->getSpecs();
611         }
612
613         // create the handle
614         sound = new AUD_OpenALHandle; AUD_NEW("handle")
615         sound->keep = keep;
616         sound->reader = reader;
617         sound->current = 0;
618         sound->isBuffered = false;
619         sound->data_end = false;
620
621         valid &= getFormat(sound->format, specs);
622
623         if(!valid)
624         {
625                 delete sound; AUD_DELETE("handle")
626                 delete reader; AUD_DELETE("reader")
627                 return NULL;
628         }
629
630         lock();
631         alcSuspendContext(m_context);
632
633         // OpenAL playback code
634         try
635         {
636                 alGenBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
637                 if(alGetError() != AL_NO_ERROR)
638                         AUD_THROW(AUD_ERROR_OPENAL);
639
640                 try
641                 {
642                         sample_t* buf;
643                         int length;
644
645                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
646                         {
647                                 length = m_buffersize;
648                                 reader->read(length, buf);
649                                 alBufferData(sound->buffers[i], sound->format, buf,
650                                                          length * AUD_SAMPLE_SIZE(specs), specs.rate);
651                                 if(alGetError() != AL_NO_ERROR)
652                                         AUD_THROW(AUD_ERROR_OPENAL);
653                         }
654
655                         alGenSources(1, &sound->source);
656                         if(alGetError() != AL_NO_ERROR)
657                                 AUD_THROW(AUD_ERROR_OPENAL);
658
659                         try
660                         {
661                                 alSourceQueueBuffers(sound->source, AUD_OPENAL_CYCLE_BUFFERS,
662                                                                          sound->buffers);
663                                 if(alGetError() != AL_NO_ERROR)
664                                         AUD_THROW(AUD_ERROR_OPENAL);
665                         }
666                         catch(AUD_Exception)
667                         {
668                                 alDeleteSources(1, &sound->source);
669                                 throw;
670                         }
671                 }
672                 catch(AUD_Exception)
673                 {
674                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
675                         throw;
676                 }
677         }
678         catch(AUD_Exception)
679         {
680                 delete sound; AUD_DELETE("handle")
681                 delete reader; AUD_DELETE("reader")
682                 alcProcessContext(m_context);
683                 unlock();
684                 throw;
685         }
686
687         // play sound
688         m_playingSounds->push_back(sound);
689         alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
690
691         start();
692
693         alcProcessContext(m_context);
694         unlock();
695
696         return sound;
697 }
698
699 bool AUD_OpenALDevice::pause(AUD_Handle* handle)
700 {
701         bool result = false;
702
703         lock();
704
705         // only songs that are played can be paused
706         for(AUD_HandleIterator i = m_playingSounds->begin();
707                 i != m_playingSounds->end(); i++)
708         {
709                 if(*i == handle)
710                 {
711                         m_pausedSounds->push_back(*i);
712                         alSourcePause((*i)->source);
713                         m_playingSounds->erase(i);
714                         result = true;
715                         break;
716                 }
717         }
718
719         unlock();
720
721         return result;
722 }
723
724 bool AUD_OpenALDevice::resume(AUD_Handle* handle)
725 {
726         bool result = false;
727
728         lock();
729
730         // only songs that are paused can be resumed
731         for(AUD_HandleIterator i = m_pausedSounds->begin();
732                 i != m_pausedSounds->end(); i++)
733         {
734                 if(*i == handle)
735                 {
736                         m_playingSounds->push_back(*i);
737                         start();
738                         m_pausedSounds->erase(i);
739                         result = true;
740                         break;
741                 }
742         }
743
744         unlock();
745
746         return result;
747 }
748
749 bool AUD_OpenALDevice::stop(AUD_Handle* handle)
750 {
751         AUD_OpenALHandle* sound;
752
753         bool result = false;
754
755         lock();
756
757         for(AUD_HandleIterator i = m_playingSounds->begin();
758                 i != m_playingSounds->end(); i++)
759         {
760                 if(*i == handle)
761                 {
762                         sound = *i;
763                         alDeleteSources(1, &sound->source);
764                         if(!sound->isBuffered)
765                         {
766                                 delete sound->reader; AUD_DELETE("reader")
767                                 alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
768                         }
769                         delete *i; AUD_DELETE("handle")
770                         m_playingSounds->erase(i);
771                         result = true;
772                         break;
773                 }
774         }
775         if(!result)
776         {
777                 for(AUD_HandleIterator i = m_pausedSounds->begin();
778                         i != m_pausedSounds->end(); i++)
779                 {
780                         if(*i == handle)
781                         {
782                                 sound = *i;
783                                 alDeleteSources(1, &sound->source);
784                                 if(!sound->isBuffered)
785                                 {
786                                         delete sound->reader; AUD_DELETE("reader")
787                                         alDeleteBuffers(AUD_OPENAL_CYCLE_BUFFERS, sound->buffers);
788                                 }
789                                 delete *i; AUD_DELETE("handle")
790                                 m_pausedSounds->erase(i);
791                                 result = true;
792                                 break;
793                         }
794                 }
795         }
796
797         unlock();
798
799         return result;
800 }
801
802 bool AUD_OpenALDevice::setKeep(AUD_Handle* handle, bool keep)
803 {
804         bool result = false;
805
806         lock();
807
808         if(isValid(handle))
809         {
810                 ((AUD_OpenALHandle*)handle)->keep = keep;
811                 result = true;
812         }
813
814         unlock();
815
816         return result;
817 }
818
819 bool AUD_OpenALDevice::sendMessage(AUD_Handle* handle, AUD_Message &message)
820 {
821         bool result = false;
822
823         lock();
824
825         if(handle == 0)
826         {
827                 for(AUD_HandleIterator i = m_playingSounds->begin();
828                         i != m_playingSounds->end(); i++)
829                         if(!(*i)->isBuffered)
830                                 result |= (*i)->reader->notify(message);
831                 for(AUD_HandleIterator i = m_pausedSounds->begin();
832                         i != m_pausedSounds->end(); i++)
833                         if(!(*i)->isBuffered)
834                                 result |= (*i)->reader->notify(message);
835         }
836         else if(isValid(handle))
837                 if(!((AUD_OpenALHandle*)handle)->isBuffered)
838                         result = ((AUD_OpenALHandle*)handle)->reader->notify(message);
839
840         unlock();
841
842         return result;
843 }
844
845 bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position)
846 {
847         bool result = false;
848
849         lock();
850
851         if(isValid(handle))
852         {
853                 AUD_OpenALHandle* alhandle = (AUD_OpenALHandle*)handle;
854                 if(alhandle->isBuffered)
855                         alSourcef(alhandle->source, AL_SEC_OFFSET, position);
856                 else
857                 {
858                         alhandle->reader->seek((int)(position *
859                                                                                  alhandle->reader->getSpecs().rate));
860                         alhandle->data_end = false;
861
862                         ALint info;
863
864                         alGetSourcei(alhandle->source, AL_SOURCE_STATE, &info);
865
866                         if(info != AL_PLAYING)
867                         {
868                                 if(info != AL_STOPPED)
869                                         alSourceStop(alhandle->source);
870
871                                 alSourceUnqueueBuffers(alhandle->source,
872                                                                            AUD_OPENAL_CYCLE_BUFFERS,
873                                                                            alhandle->buffers);
874                                 if(alGetError() == AL_NO_ERROR)
875                                 {
876                                         sample_t* buf;
877                                         int length;
878                                         AUD_Specs specs = alhandle->reader->getSpecs();
879
880                                         for(int i = 0; i < AUD_OPENAL_CYCLE_BUFFERS; i++)
881                                         {
882                                                 length = m_buffersize;
883                                                 alhandle->reader->read(length, buf);
884                                                 alBufferData(alhandle->buffers[i], alhandle->format,
885                                                                          buf, length * AUD_SAMPLE_SIZE(specs),
886                                                                          specs.rate);
887
888                                                 if(alGetError() != AL_NO_ERROR)
889                                                         break;
890                                         }
891
892                                         alSourceQueueBuffers(alhandle->source,
893                                                                                  AUD_OPENAL_CYCLE_BUFFERS,
894                                                                                  alhandle->buffers);
895                                 }
896
897                                 alSourceRewind(alhandle->source);
898                         }
899                 }
900                 result = true;
901         }
902
903         unlock();
904         return result;
905 }
906
907 float AUD_OpenALDevice::getPosition(AUD_Handle* handle)
908 {
909         float position = 0.0;
910
911         lock();
912
913         if(isValid(handle))
914         {
915                 AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
916                 if(h->isBuffered)
917                         alGetSourcef(h->source, AL_SEC_OFFSET, &position);
918                 else
919                         position = h->reader->getPosition() /
920                                            (float)h->reader->getSpecs().rate;
921         }
922
923         unlock();
924         return position;
925 }
926
927 AUD_Status AUD_OpenALDevice::getStatus(AUD_Handle* handle)
928 {
929         AUD_Status status = AUD_STATUS_INVALID;
930
931         lock();
932
933         for(AUD_HandleIterator i = m_playingSounds->begin();
934                 i != m_playingSounds->end(); i++)
935         {
936                 if(*i == handle)
937                 {
938                         status = AUD_STATUS_PLAYING;
939                         break;
940                 }
941         }
942         if(status == AUD_STATUS_INVALID)
943         {
944                 for(AUD_HandleIterator i = m_pausedSounds->begin();
945                         i != m_pausedSounds->end(); i++)
946                 {
947                         if(*i == handle)
948                         {
949                                 status = AUD_STATUS_PAUSED;
950                                 break;
951                         }
952                 }
953         }
954
955         unlock();
956
957         return status;
958 }
959
960 void AUD_OpenALDevice::lock()
961 {
962         pthread_mutex_lock(&m_mutex);
963 }
964
965 void AUD_OpenALDevice::unlock()
966 {
967         pthread_mutex_unlock(&m_mutex);
968 }
969
970 /******************************************************************************/
971 /**************************** Capabilities Code *******************************/
972 /******************************************************************************/
973
974 bool AUD_OpenALDevice::checkCapability(int capability)
975 {
976         return capability == AUD_CAPS_3D_DEVICE ||
977                    capability == AUD_CAPS_VOLUME ||
978                    capability == AUD_CAPS_SOURCE_VOLUME ||
979                    capability == AUD_CAPS_SOURCE_PITCH ||
980                    capability == AUD_CAPS_BUFFERED_FACTORY;
981 }
982
983 bool AUD_OpenALDevice::setCapability(int capability, void *value)
984 {
985         bool result = false;
986         switch(capability)
987         {
988         case AUD_CAPS_VOLUME:
989                 alListenerf(AL_GAIN, *((float*)value));
990                 return true;
991         case AUD_CAPS_SOURCE_VOLUME:
992                 {
993                         AUD_SourceCaps* caps = (AUD_SourceCaps*) value;
994                         lock();
995                         if(isValid(caps->handle))
996                         {
997                                 alSourcef(((AUD_OpenALHandle*)caps->handle)->source,
998                                                   AL_GAIN, caps->value);
999                                 result = true;
1000                         }
1001                         unlock();
1002                 }
1003                 break;
1004         case AUD_CAPS_SOURCE_PITCH:
1005                 {
1006                         AUD_SourceCaps* caps = (AUD_SourceCaps*) value;
1007                         lock();
1008                         if(isValid(caps->handle))
1009                         {
1010                                 alSourcef(((AUD_OpenALHandle*)caps->handle)->source,
1011                                                   AL_PITCH, caps->value);
1012                                 result = true;
1013                         }
1014                         unlock();
1015                 }
1016                 break;
1017         case AUD_CAPS_BUFFERED_FACTORY:
1018                 {
1019                         AUD_IFactory* factory = (AUD_IFactory*) value;
1020
1021                         // load the factory into an OpenAL buffer
1022                         if(factory)
1023                         {
1024                                 lock();
1025                                 for(AUD_BFIterator i = m_bufferedFactories->begin();
1026                                         i != m_bufferedFactories->end(); i++)
1027                                 {
1028                                         if((*i)->factory == factory)
1029                                         {
1030                                                 result = true;
1031                                                 break;
1032                                         }
1033                                 }
1034                                 unlock();
1035                                 if(result)
1036                                         return result;
1037
1038                                 AUD_IReader* reader = factory->createReader();
1039
1040                                 if(reader == NULL)
1041                                         return false;
1042
1043                                 AUD_Specs specs;
1044
1045                                 specs = reader->getSpecs();
1046
1047                                 // determine format
1048                                 bool valid = reader->getType() == AUD_TYPE_BUFFER;
1049
1050                                 if(valid)
1051                                 {
1052                                         if(specs.format == AUD_FORMAT_INVALID)
1053                                                 valid = false;
1054                                         else if(specs.format == AUD_FORMAT_S24 ||
1055                                                         specs.format == AUD_FORMAT_S32 ||
1056                                                         specs.format == AUD_FORMAT_FLOAT32 ||
1057                                                         specs.format == AUD_FORMAT_FLOAT64)
1058                                         {
1059                                                 m_converter->setReader(reader);
1060                                                 reader = m_converter->createReader();
1061                                                 specs = reader->getSpecs();
1062                                         }
1063                                 }
1064
1065                                 ALenum format;
1066
1067                                 if(valid)
1068                                         valid = getFormat(format, specs);
1069
1070                                 if(!valid)
1071                                 {
1072                                         delete reader; AUD_DELETE("reader")
1073                                         return false;
1074                                 }
1075
1076                                 // load into a buffer
1077                                 lock();
1078                                 alcSuspendContext(m_context);
1079
1080                                 AUD_OpenALBufferedFactory* bf = new AUD_OpenALBufferedFactory;
1081                                 AUD_NEW("bufferedfactory");
1082                                 bf->factory = factory;
1083
1084                                 try
1085                                 {
1086                                         alGenBuffers(1, &bf->buffer);
1087                                         if(alGetError() != AL_NO_ERROR)
1088                                                 AUD_THROW(AUD_ERROR_OPENAL);
1089
1090                                         try
1091                                         {
1092                                                 sample_t* buf;
1093                                                 int length = reader->getLength();
1094
1095                                                 reader->read(length, buf);
1096                                                 alBufferData(bf->buffer, format, buf,
1097                                                                          length * AUD_SAMPLE_SIZE(specs),
1098                                                                          specs.rate);
1099                                                 if(alGetError() != AL_NO_ERROR)
1100                                                         AUD_THROW(AUD_ERROR_OPENAL);
1101                                         }
1102                                         catch(AUD_Exception)
1103                                         {
1104                                                 alDeleteBuffers(1, &bf->buffer);
1105                                                 throw;
1106                                         }
1107                                 }
1108                                 catch(AUD_Exception)
1109                                 {
1110                                         delete bf; AUD_DELETE("bufferedfactory")
1111                                         delete reader; AUD_DELETE("reader")
1112                                         alcProcessContext(m_context);
1113                                         unlock();
1114                                         return false;
1115                                 }
1116
1117                                 m_bufferedFactories->push_back(bf);
1118
1119                                 alcProcessContext(m_context);
1120                                 unlock();
1121                         }
1122                         else
1123                         {
1124                                 // stop all playing and paused buffered sources
1125                                 lock();
1126                                 alcSuspendContext(m_context);
1127
1128                                 AUD_OpenALHandle* sound;
1129                                 AUD_HandleIterator it = m_playingSounds->begin();
1130                                 while(it != m_playingSounds->end())
1131                                 {
1132                                         sound = *it;
1133                                         ++it;
1134
1135                                         if(sound->isBuffered)
1136                                                 stop(sound);
1137                                 }
1138                                 alcProcessContext(m_context);
1139
1140                                 while(!m_bufferedFactories->empty())
1141                                 {
1142                                         alDeleteBuffers(1,
1143                                                                         &(*(m_bufferedFactories->begin()))->buffer);
1144                                         delete *m_bufferedFactories->begin();
1145                                         AUD_DELETE("bufferedfactory");
1146                                         m_bufferedFactories->erase(m_bufferedFactories->begin());
1147                                 }
1148                                 unlock();
1149                         }
1150
1151                         return true;
1152                 }
1153                 break;
1154         }
1155         return result;
1156 }
1157
1158 bool AUD_OpenALDevice::getCapability(int capability, void *value)
1159 {
1160         bool result = false;
1161
1162         switch(capability)
1163         {
1164         case AUD_CAPS_VOLUME:
1165                 alGetListenerf(AL_GAIN, (float*)value);
1166                 return true;
1167         case AUD_CAPS_SOURCE_VOLUME:
1168                 {
1169                         AUD_SourceCaps* caps = (AUD_SourceCaps*) value;
1170                         lock();
1171                         if(isValid(caps->handle))
1172                         {
1173                                 alGetSourcef(((AUD_OpenALHandle*)caps->handle)->source,
1174                                                   AL_GAIN, &caps->value);
1175                                 result = true;
1176                         }
1177                         unlock();
1178                 }
1179                 break;
1180         case AUD_CAPS_SOURCE_PITCH:
1181                 {
1182                         AUD_SourceCaps* caps = (AUD_SourceCaps*) value;
1183                         lock();
1184                         if(isValid(caps->handle))
1185                         {
1186                                 alGetSourcef(((AUD_OpenALHandle*)caps->handle)->source,
1187                                                   AL_PITCH, &caps->value);
1188                                 result = true;
1189                         }
1190                         unlock();
1191                 }
1192                 break;
1193         }
1194
1195         return result;
1196 }
1197
1198 /******************************************************************************/
1199 /**************************** 3D Device Code **********************************/
1200 /******************************************************************************/
1201
1202 AUD_Handle* AUD_OpenALDevice::play3D(AUD_IFactory* factory, bool keep)
1203 {
1204         AUD_OpenALHandle* handle = (AUD_OpenALHandle*)play(factory, keep);
1205         if(handle)
1206                 alSourcei(handle->source, AL_SOURCE_RELATIVE, 0);
1207         return handle;
1208 }
1209
1210 bool AUD_OpenALDevice::updateListener(AUD_3DData &data)
1211 {
1212         alListenerfv(AL_POSITION, (ALfloat*)data.position);
1213         alListenerfv(AL_VELOCITY, (ALfloat*)data.velocity);
1214         alListenerfv(AL_ORIENTATION, (ALfloat*)&(data.orientation[3]));
1215
1216         return true;
1217 }
1218
1219 bool AUD_OpenALDevice::setSetting(AUD_3DSetting setting, float value)
1220 {
1221         switch(setting)
1222         {
1223         case AUD_3DS_DISTANCE_MODEL:
1224                 if(value == AUD_DISTANCE_MODEL_NONE)
1225                         alDistanceModel(AL_NONE);
1226                 else if(value == AUD_DISTANCE_MODEL_INVERSE)
1227                         alDistanceModel(AL_INVERSE_DISTANCE);
1228                 else if(value == AUD_DISTANCE_MODEL_INVERSE_CLAMPED)
1229                         alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
1230                 else if(value == AUD_DISTANCE_MODEL_LINEAR)
1231                         alDistanceModel(AL_LINEAR_DISTANCE);
1232                 else if(value == AUD_DISTANCE_MODEL_LINEAR_CLAMPED)
1233                         alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
1234                 else if(value == AUD_DISTANCE_MODEL_EXPONENT)
1235                         alDistanceModel(AL_EXPONENT_DISTANCE);
1236                 else if(value == AUD_DISTANCE_MODEL_EXPONENT_CLAMPED)
1237                         alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
1238                 else
1239                         return false;
1240                 return true;
1241         case AUD_3DS_DOPPLER_FACTOR:
1242                 alDopplerFactor(value);
1243                 return true;
1244         case AUD_3DS_SPEED_OF_SOUND:
1245                 alSpeedOfSound(value);
1246                 return true;
1247         default:
1248                 return false;
1249         }
1250 }
1251
1252 float AUD_OpenALDevice::getSetting(AUD_3DSetting setting)
1253 {
1254         switch(setting)
1255         {
1256         case AUD_3DS_DISTANCE_MODEL:
1257                 switch(alGetInteger(AL_DISTANCE_MODEL))
1258                 {
1259                         case AL_NONE:
1260                                 return AUD_DISTANCE_MODEL_NONE;
1261                         case AL_INVERSE_DISTANCE:
1262                                 return AUD_DISTANCE_MODEL_INVERSE;
1263                         case AL_INVERSE_DISTANCE_CLAMPED:
1264                                 return AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
1265                         case AL_LINEAR_DISTANCE:
1266                                 return AUD_DISTANCE_MODEL_LINEAR;
1267                         case AL_LINEAR_DISTANCE_CLAMPED:
1268                                 return AUD_DISTANCE_MODEL_LINEAR_CLAMPED;
1269                         case AL_EXPONENT_DISTANCE:
1270                                 return AUD_DISTANCE_MODEL_EXPONENT;
1271                         case AL_EXPONENT_DISTANCE_CLAMPED:
1272                                 return AUD_DISTANCE_MODEL_EXPONENT_CLAMPED;
1273                 }
1274         case AUD_3DS_DOPPLER_FACTOR:
1275                 return alGetFloat(AL_DOPPLER_FACTOR);
1276         case AUD_3DS_SPEED_OF_SOUND:
1277                 return alGetFloat(AL_SPEED_OF_SOUND);
1278         default:
1279                 return std::numeric_limits<float>::quiet_NaN();
1280         }
1281 }
1282
1283 bool AUD_OpenALDevice::updateSource(AUD_Handle* handle, AUD_3DData &data)
1284 {
1285         bool result = false;
1286
1287         lock();
1288
1289         if(isValid(handle))
1290         {
1291                 int source = ((AUD_OpenALHandle*)handle)->source;
1292                 alSourcefv(source, AL_POSITION, (ALfloat*)data.position);
1293                 alSourcefv(source, AL_VELOCITY, (ALfloat*)data.velocity);
1294                 alSourcefv(source, AL_DIRECTION, (ALfloat*)&(data.orientation[3]));
1295                 result = true;
1296         }
1297
1298         unlock();
1299
1300         return result;
1301 }
1302
1303 bool AUD_OpenALDevice::setSourceSetting(AUD_Handle* handle,
1304                                                                                 AUD_3DSourceSetting setting,
1305                                                                                 float value)
1306 {
1307         lock();
1308
1309         bool result = false;
1310
1311         if(isValid(handle))
1312         {
1313                 int source = ((AUD_OpenALHandle*)handle)->source;
1314
1315                 switch(setting)
1316                 {
1317                 case AUD_3DSS_CONE_INNER_ANGLE:
1318                         alSourcef(source, AL_CONE_INNER_ANGLE, value);
1319                         result = true;
1320                         break;
1321                 case AUD_3DSS_CONE_OUTER_ANGLE:
1322                         alSourcef(source, AL_CONE_OUTER_ANGLE, value);
1323                         result = true;
1324                         break;
1325                 case AUD_3DSS_CONE_OUTER_GAIN:
1326                         alSourcef(source, AL_CONE_OUTER_GAIN, value);
1327                         result = true;
1328                         break;
1329                 case AUD_3DSS_IS_RELATIVE:
1330                         alSourcei(source, AL_SOURCE_RELATIVE, value > 0.0);
1331                         result = true;
1332                         break;
1333                 case AUD_3DSS_MAX_DISTANCE:
1334                         alSourcef(source, AL_MAX_DISTANCE, value);
1335                         result = true;
1336                         break;
1337                 case AUD_3DSS_MAX_GAIN:
1338                         alSourcef(source, AL_MAX_GAIN, value);
1339                         result = true;
1340                         break;
1341                 case AUD_3DSS_MIN_GAIN:
1342                         alSourcef(source, AL_MIN_GAIN, value);
1343                         result = true;
1344                         break;
1345                 case AUD_3DSS_REFERENCE_DISTANCE:
1346                         alSourcef(source, AL_REFERENCE_DISTANCE, value);
1347                         result = true;
1348                         break;
1349                 case AUD_3DSS_ROLLOFF_FACTOR:
1350                         alSourcef(source, AL_ROLLOFF_FACTOR, value);
1351                         result = true;
1352                         break;
1353                 default:
1354                         break;
1355                 }
1356         }
1357
1358         unlock();
1359         return result;
1360 }
1361
1362 float AUD_OpenALDevice::getSourceSetting(AUD_Handle* handle,
1363                                                                                  AUD_3DSourceSetting setting)
1364 {
1365         float result = std::numeric_limits<float>::quiet_NaN();;
1366
1367         lock();
1368
1369         if(isValid(handle))
1370         {
1371                 int source = ((AUD_OpenALHandle*)handle)->source;
1372
1373                 switch(setting)
1374                 {
1375                 case AUD_3DSS_CONE_INNER_ANGLE:
1376                         alGetSourcef(source, AL_CONE_INNER_ANGLE, &result);
1377                         break;
1378                 case AUD_3DSS_CONE_OUTER_ANGLE:
1379                         alGetSourcef(source, AL_CONE_OUTER_ANGLE, &result);
1380                         break;
1381                 case AUD_3DSS_CONE_OUTER_GAIN:
1382                         alGetSourcef(source, AL_CONE_OUTER_GAIN, &result);
1383                         break;
1384                 case AUD_3DSS_IS_RELATIVE:
1385                         {
1386                                 ALint i;
1387                                 alGetSourcei(source, AL_SOURCE_RELATIVE, &i);
1388                                 result = i ? 1.0 : 0.0;
1389                                 break;
1390                         }
1391                 case AUD_3DSS_MAX_DISTANCE:
1392                         alGetSourcef(source, AL_MAX_DISTANCE, &result);
1393                         break;
1394                 case AUD_3DSS_MAX_GAIN:
1395                         alGetSourcef(source, AL_MAX_GAIN, &result);
1396                         break;
1397                 case AUD_3DSS_MIN_GAIN:
1398                         alGetSourcef(source, AL_MIN_GAIN, &result);
1399                         break;
1400                 case AUD_3DSS_REFERENCE_DISTANCE:
1401                         alGetSourcef(source, AL_REFERENCE_DISTANCE, &result);
1402                         break;
1403                 case AUD_3DSS_ROLLOFF_FACTOR:
1404                         alGetSourcef(source, AL_ROLLOFF_FACTOR, &result);
1405                         break;
1406                 default:
1407                         break;
1408                 }
1409         }
1410
1411         unlock();
1412         return result;
1413 }