1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2004 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "OpenALAudio.h"
25 bool checkALError(const char* msg
, const char* status
) {
26 int error
= alGetError();
27 if (error
!= AL_NO_ERROR
) {
28 printMessage("OpenAL", msg
, WHITE
);
29 printf (": %d ", error
);
30 printStatus(status
, YELLOW
);
36 void showALCError(const char* msg
, const char* status
, ALCdevice
*device
) {
37 int error
= alcGetError(device
);
38 printMessage("OpenAL", msg
, WHITE
);
39 if (error
!= AL_NO_ERROR
) {
40 printf (": %d ", error
);
42 printStatus(status
, YELLOW
);
45 void AudioStream::ClearProcessedBuffers()
48 alGetSourcei( Source
, AL_BUFFERS_PROCESSED
, &processed
);
50 checkALError("Failed to get processed buffers", "WARNING");
53 ALuint
* b
= new ALuint
[processed
];
54 alSourceUnqueueBuffers( Source
, processed
, b
);
55 checkALError("Failed to unqueue buffers", "WARNING");
58 alDeleteBuffers(processed
, b
);
59 checkALError("Failed to delete buffers", "WARNING");
67 void AudioStream::ClearIfStopped()
69 if (free
|| locked
) return;
71 if (!alIsSource(Source
)) return;
74 alGetSourcei( Source
, AL_SOURCE_STATE
, &state
);
75 if (!checkALError("Failed to check source state", "WARNING") &&
78 ClearProcessedBuffers();
79 alDeleteSources( 1, &Source
);
80 checkALError("Failed to delete source", "WARNING");
86 delete_buffers
= false;
90 void AudioStream::ForceClear()
92 if (!alIsSource(Source
)) return;
95 checkALError("Failed to stop source", "WARNING");
96 ClearProcessedBuffers();
100 OpenALAudioDriver::OpenALAudioDriver(void)
103 MusicPlaying
= false;
104 music_memory
= (unsigned char*) malloc(ACM_BUFFERSIZE
);
106 memset(MusicBuffer
, 0, MUSICBUFFERS
*sizeof(ALuint
));
107 musicMutex
= SDL_CreateMutex();
112 bool OpenALAudioDriver::Init(void)
117 device
= alcOpenDevice (NULL
);
118 if (device
== NULL
) {
119 showALCError("Failed to open device", "ERROR", device
);
123 context
= alcCreateContext (device
, NULL
);
124 if (context
== NULL
) {
125 showALCError("Failed to create context", "ERROR", device
);
126 alcCloseDevice (device
);
130 if (!alcMakeContextCurrent (context
)) {
131 showALCError("Failed to select context", "ERROR", device
);
132 alcDestroyContext (context
);
133 alcCloseDevice (device
);
136 alutContext
= context
;
139 int sources
= CountAvailableSources(MAX_STREAMS
+1);
140 num_streams
= sources
- 1;
143 sprintf(buf
, "Allocated %d streams.%s", num_streams
,
144 (num_streams
< MAX_STREAMS
? " (Fewer than desired.)" : "" ) );
146 printMessage( "OpenAL", buf
, WHITE
);
149 musicThread
= SDL_CreateThread( MusicManager
, this );
151 ambim
= new AmbientMgrAL
;
153 speech
.ambient
= false;
157 int OpenALAudioDriver::CountAvailableSources(int limit
)
159 ALuint
* src
= new ALuint
[limit
+2];
161 for (i
= 0; i
< limit
+2; ++i
) {
162 alGenSources(1, &src
[i
]);
163 if (alGetError() != AL_NO_ERROR
)
167 alDeleteSources(i
, src
);
170 // Leave two sources free for internal OpenAL usage
171 // (Might not be strictly necessary...)
174 checkALError("Error while auto-detecting number of sources", "WARNING");
176 // Return number of succesfully allocated sources
180 OpenALAudioDriver::~OpenALAudioDriver(void)
183 // initialisation must have failed
187 for(int i
=0; i
<num_streams
; i
++) {
188 streams
[i
].ForceClear();
192 clearBufferCache(true);
196 alcMakeContextCurrent (NULL
);
198 device
= alcGetContextsDevice (alutContext
);
199 alcDestroyContext (alutContext
);
200 if (alcGetError (device
) == ALC_NO_ERROR
) {
201 alcCloseDevice (device
);
204 SDL_mutexP(musicMutex
);
205 SDL_KillThread(musicThread
);
206 SDL_mutexV(musicMutex
);
208 SDL_DestroyMutex(musicMutex
);
213 core
->FreeInterface(MusicReader
);
218 ALuint
OpenALAudioDriver::loadSound(const char *ResRef
, unsigned int &time_length
)
228 if(buffercache
.Lookup(ResRef
, p
))
231 time_length
= e
->Length
;
235 DataStream
* stream
= gamedata
->GetResource(ResRef
, IE_WAV_CLASS_ID
);
237 stream
= gamedata
->GetResource(ResRef
, IE_OGG_CLASS_ID
);
241 alGenBuffers(1, &Buffer
);
242 if (checkALError("Unable to create sound buffer", "ERROR")) {
247 SoundMgr
* acm
= (SoundMgr
*) core
->GetInterface(IE_WAV_CLASS_ID
);
248 if (!acm
->Open(stream
)) {
249 core
->FreeInterface(acm
);
250 alDeleteBuffers( 1, &Buffer
);
253 int cnt
= acm
->get_length();
254 int riff_chans
= acm
->get_channels();
255 int samplerate
= acm
->get_samplerate();
256 //multiply always by 2 because it is in 16 bits
257 int rawsize
= cnt
* 2;
258 unsigned char * memory
= (unsigned char*) malloc(rawsize
);
259 //multiply always with 2 because it is in 16 bits
260 int cnt1
= acm
->read_samples( ( short* ) memory
, cnt
) * 2;
261 //Sound Length in milliseconds
262 time_length
= ((cnt
/ riff_chans
) * 1000) / samplerate
;
263 //it is always reading the stuff into 16 bits
264 alBufferData( Buffer
, GetFormatEnum( riff_chans
, 16 ), memory
, cnt1
, samplerate
);
265 core
->FreeInterface( acm
);
268 if (checkALError("Unable to fill buffer", "ERROR")) {
269 alDeleteBuffers( 1, &Buffer
);
270 checkALError("Error deleting buffer", "WARNING");
276 e
->Length
= ((cnt
/ riff_chans
) * 1000) / samplerate
;
278 buffercache
.SetAt(ResRef
, (void*)e
);
279 //printf("LoadSound: added %s to cache: %d. Cache size now %d\n", ResRef, e->Buffer, buffercache.GetCount());
281 if (buffercache
.GetCount() > BUFFER_CACHE_SIZE
) {
287 unsigned int OpenALAudioDriver::Play(const char* ResRef
, int XPos
, int YPos
, unsigned int flags
)
290 unsigned int time_length
;
293 if((flags
& GEM_SND_SPEECH
) && alIsSource(speech
.Source
)) {
294 //So we want him to be quiet...
295 alSourceStop( speech
.Source
);
296 checkALError("Unable to stop speech", "WARNING");
297 speech
.ClearProcessedBuffers();
302 Buffer
= loadSound( ResRef
, time_length
);
308 ALfloat SourcePos
[] = {
309 (float) XPos
, (float) YPos
, 0.0f
311 ALfloat SourceVel
[] = {
315 ieDword volume
= 100;
317 if (flags
& GEM_SND_SPEECH
) {
318 //speech has a single channel, if a new speech started
319 //we stop the previous one
320 if(!speech
.free
&& alIsSource(speech
.Source
)) {
321 alSourceStop( speech
.Source
);
322 checkALError("Unable to stop speech", "WARNING");
323 speech
.ClearProcessedBuffers();
325 if(!alIsSource(speech
.Source
)) {
326 alGenSources( 1, &speech
.Source
);
327 if (checkALError("Error creating source for speech", "ERROR")) {
332 alSourcef( speech
.Source
, AL_PITCH
, 1.0f
);
333 alSourcefv( speech
.Source
, AL_VELOCITY
, SourceVel
);
334 alSourcei( speech
.Source
, AL_LOOPING
, 0 );
335 alSourcef( speech
.Source
, AL_REFERENCE_DISTANCE
, REFERENCE_DISTANCE
);
336 checkALError("Unable to set speech parameters", "WARNING");
338 printf("speech.free: %d source:%d\n", speech
.free
,speech
.Source
);
340 core
->GetDictionary()->Lookup( "Volume Voices", volume
);
341 alSourcef( speech
.Source
, AL_GAIN
, 0.01f
* volume
);
342 alSourcei( speech
.Source
, AL_SOURCE_RELATIVE
, flags
& GEM_SND_RELATIVE
);
343 alSourcefv( speech
.Source
, AL_POSITION
, SourcePos
);
344 assert(!speech
.delete_buffers
);
345 alSourcei( speech
.Source
, AL_BUFFER
, Buffer
);
346 checkALError("Unable to set speech parameters", "WARNING");
347 speech
.Buffer
= Buffer
;
348 alSourcePlay( speech
.Source
);
349 if (checkALError("Unable to play speech", "ERROR")) {
356 for (int i
= 0; i
< num_streams
; i
++) {
357 streams
[i
].ClearIfStopped();
358 if (streams
[i
].free
) {
365 // Failed to assign new sound.
366 // The buffercache will handle deleting Buffer.
371 alGenSources( 1, &Source
);
372 if (checkALError("Unable to create source", "ERROR")) {
376 alSourcef( Source
, AL_PITCH
, 1.0f
);
377 alSourcefv( Source
, AL_VELOCITY
, SourceVel
);
378 alSourcei( Source
, AL_LOOPING
, 0 );
379 alSourcef( Source
, AL_REFERENCE_DISTANCE
, REFERENCE_DISTANCE
);
380 core
->GetDictionary()->Lookup( "Volume SFX", volume
);
381 alSourcef( Source
, AL_GAIN
, 0.01f
* volume
);
382 alSourcei( Source
, AL_SOURCE_RELATIVE
, flags
& GEM_SND_RELATIVE
);
383 alSourcefv( Source
, AL_POSITION
, SourcePos
);
384 assert(!streams
[stream
].delete_buffers
);
385 alSourcei( Source
, AL_BUFFER
, Buffer
);
387 if (checkALError("Unable to set sound parameters", "ERROR")) {
391 streams
[stream
].Buffer
= Buffer
;
392 streams
[stream
].Source
= Source
;
393 streams
[stream
].free
= false;
394 alSourcePlay( Source
);
396 if (checkALError("Unable to play sound", "ERROR")) {
403 bool OpenALAudioDriver::IsSpeaking()
405 speech
.ClearIfStopped();
409 void OpenALAudioDriver::UpdateVolume(unsigned int flags
)
413 if (flags
& GEM_SND_VOL_MUSIC
) {
414 SDL_mutexP( musicMutex
);
415 core
->GetDictionary()->Lookup("Volume Music", volume
);
416 if (alIsSource(MusicSource
))
417 alSourcef(MusicSource
, AL_GAIN
, volume
* 0.01f
);
418 SDL_mutexV(musicMutex
);
421 if (flags
& GEM_SND_VOL_AMBIENTS
) {
422 core
->GetDictionary()->Lookup("Volume Ambients", volume
);
423 ((AmbientMgrAL
*) ambim
)->UpdateVolume(volume
);
427 bool OpenALAudioDriver::CanPlay()
432 void OpenALAudioDriver::ResetMusics()
434 MusicPlaying
= false;
435 SDL_mutexP( musicMutex
);
436 if (alIsSource(MusicSource
)) {
437 alSourceStop(MusicSource
);
438 checkALError("Unable to stop music source", "WARNING");
439 alDeleteSources(1, &MusicSource
);
440 checkALError("Unable to delete music source", "WARNING");
442 for (int i
=0; i
<MUSICBUFFERS
; i
++) {
443 if (alIsBuffer(MusicBuffer
[i
])) {
444 alDeleteBuffers(1, MusicBuffer
+i
);
445 checkALError("Unable to delete music buffer", "WARNING");
449 SDL_mutexV( musicMutex
);
452 bool OpenALAudioDriver::Play()
454 if (!MusicReader
) return false;
456 SDL_mutexP( musicMutex
);
459 SDL_mutexV( musicMutex
);
464 bool OpenALAudioDriver::Stop()
466 SDL_mutexP( musicMutex
);
467 if (!alIsSource( MusicSource
)) {
468 SDL_mutexV( musicMutex
);
471 alSourceStop( MusicSource
);
472 checkALError("Unable to stop music source", "WARNING");
473 MusicPlaying
= false;
474 alDeleteSources( 1, &MusicSource
);
475 checkALError("Unable to delete music source", "WARNING");
477 SDL_mutexV( musicMutex
);
481 int OpenALAudioDriver::StreamFile(const char* filename
)
483 char path
[_MAX_PATH
];
485 strcpy( path
, core
->GamePath
);
486 strcpy( path
, filename
);
487 FileStream
* str
= new FileStream();
488 if (!str
->Open( path
, true )) {
490 printMessage("OpenAL", "",WHITE
);
491 printf( "Cannot find %s", path
);
492 printStatus("NOT FOUND", YELLOW
);
495 StackLock
l(musicMutex
, "musicMutex in CreateStream()");
497 // Free old MusicReader
498 core
->FreeInterface(MusicReader
);
501 if (MusicBuffer
[0] == 0) {
502 alGenBuffers( MUSICBUFFERS
, MusicBuffer
);
503 if (checkALError("Unable to create music buffers", "ERROR")) {
508 MusicReader
= (SoundMgr
*) core
->GetInterface( IE_WAV_CLASS_ID
);
509 if (!MusicReader
->Open(str
, true)) {
511 core
->FreeInterface(MusicReader
);
513 MusicPlaying
= false;
514 printMessage("OpenAL", "",WHITE
);
515 printf( "Cannot open %s", path
);
516 printStatus("ERROR", YELLOW
);
519 if (MusicSource
== 0) {
520 alGenSources( 1, &MusicSource
);
521 if (checkALError("Unable to create music source", "ERROR")) {
525 ALfloat SourcePos
[] = {
528 ALfloat SourceVel
[] = {
533 core
->GetDictionary()->Lookup( "Volume Music", volume
);
534 alSourcef( MusicSource
, AL_PITCH
, 1.0f
);
535 alSourcef( MusicSource
, AL_GAIN
, 0.01f
* volume
);
536 alSourcei( MusicSource
, AL_SOURCE_RELATIVE
, 1 );
537 alSourcefv( MusicSource
, AL_POSITION
, SourcePos
);
538 alSourcefv( MusicSource
, AL_VELOCITY
, SourceVel
);
539 alSourcei( MusicSource
, AL_LOOPING
, 0 );
540 checkALError("Unable to set music parameters", "WARNING");
546 void OpenALAudioDriver::UpdateListenerPos(int XPos
, int YPos
)
548 alListener3f( AL_POSITION
, (float) XPos
, (float) YPos
, 0.0f
);
551 void OpenALAudioDriver::GetListenerPos(int &XPos
, int &YPos
)
554 alGetListenerfv( AL_POSITION
, listen
);
555 if (checkALError("Unable to get listener pos", "ERROR")) return;
556 XPos
= (int) listen
[0];
557 YPos
= (int) listen
[1];
560 bool OpenALAudioDriver::ReleaseStream(int stream
, bool HardStop
)
562 if (streams
[stream
].free
|| !streams
[stream
].locked
)
564 streams
[stream
].locked
= false;
566 // it's now unlocked, so it will automatically be reclaimed when needed
570 ALuint Source
= streams
[stream
].Source
;
571 alSourceStop(Source
);
572 checkALError("Unable to stop source", "WARNING");
573 streams
[stream
].ClearIfStopped();
578 //This one is used for movies and ambients.
579 int OpenALAudioDriver::SetupNewStream( ieWord x
, ieWord y
, ieWord z
,
580 ieWord gain
, bool point
, bool Ambient
)
582 // Find a free (or finished) stream for this sound
584 for (int i
= 0; i
< num_streams
; i
++) {
585 streams
[i
].ClearIfStopped();
586 if (streams
[i
].free
) {
591 if (stream
== -1) return -1;
594 alGenSources(1, &source
);
595 if (checkALError("Unable to create new source", "ERROR")) {
599 ALfloat position
[] = { (float) x
, (float) y
, (float) z
};
600 alSourcef( source
, AL_PITCH
, 1.0f
);
601 alSourcefv( source
, AL_POSITION
, position
);
602 alSourcef( source
, AL_GAIN
, 0.01f
* gain
);
603 alSourcei( source
, AL_REFERENCE_DISTANCE
, REFERENCE_DISTANCE
);
604 alSourcei( source
, AL_ROLLOFF_FACTOR
, point
? 1 : 0 );
605 alSourcei( source
, AL_LOOPING
, 0 );
606 checkALError("Unable to set stream parameters", "WARNING");
608 streams
[stream
].Buffer
= 0;
609 streams
[stream
].Source
= source
;
610 streams
[stream
].free
= false;
611 streams
[stream
].ambient
= Ambient
;
612 streams
[stream
].locked
= true;
617 int OpenALAudioDriver::QueueAmbient(int stream
, const char* sound
)
619 if (streams
[stream
].free
|| !streams
[stream
].ambient
)
622 ALuint source
= streams
[stream
].Source
;
624 // first dequeue any processed buffers
625 streams
[stream
].ClearProcessedBuffers();
630 unsigned int time_length
;
631 ALuint Buffer
= loadSound(sound
, time_length
);
636 assert(!streams
[stream
].delete_buffers
);
638 alSourceQueueBuffers(source
, 1, &Buffer
);
639 if (checkALError("Unable to queue ambient buffer","ERROR")) {
645 alGetSourcei( source
, AL_SOURCE_STATE
, &state
);
646 if (!checkALError("Unable to query ambient source state", "ERROR") &&
648 { // play on playing source would rewind it
649 alSourcePlay( source
);
650 if (checkALError("Unable to play ambient source", "ERROR"))
657 void OpenALAudioDriver::SetAmbientStreamVolume(int stream
, int volume
)
659 if (streams
[stream
].free
|| !streams
[stream
].ambient
)
662 ALuint source
= streams
[stream
].Source
;
663 alSourcef( source
, AL_GAIN
, 0.01f
* volume
);
664 checkALError("Unable to set ambient volume", "WARNING");
667 bool OpenALAudioDriver::evictBuffer()
669 // Note: this function assumes the caller holds bufferMutex
671 // Room for optimization: this is O(n^2) in the number of buffers
672 // at the tail that are used. It can be O(n) if LRUCache supports it.
679 while ((res
= buffercache
.getLRU(n
, k
, p
)) == true) {
680 CacheEntry
* e
= (CacheEntry
*)p
;
681 alDeleteBuffers(1, &e
->Buffer
);
682 if (alGetError() == AL_NO_ERROR
) {
683 // Buffer was unused. An error would have indicated
684 // the buffer was still attached to a source.
687 buffercache
.Remove(k
);
689 //printf("Removed buffer %s from ACMImp cache\n", k);
698 void OpenALAudioDriver::clearBufferCache(bool force
)
700 // Room for optimization: any method of iterating over the buffers
701 // would suffice. It doesn't have to be in LRU-order.
705 while (buffercache
.getLRU(n
, k
, p
)) {
706 CacheEntry
* e
= (CacheEntry
*)p
;
707 alDeleteBuffers(1, &e
->Buffer
);
708 if (force
|| alGetError() == AL_NO_ERROR
) {
710 buffercache
.Remove(k
);
716 ALenum
OpenALAudioDriver::GetFormatEnum(int channels
, int bits
)
721 return AL_FORMAT_MONO8
;
723 return AL_FORMAT_MONO16
;
728 return AL_FORMAT_STEREO8
;
730 return AL_FORMAT_STEREO16
;
733 return AL_FORMAT_MONO8
;
736 int OpenALAudioDriver::MusicManager(void* arg
)
738 OpenALAudioDriver
* driver
= (OpenALAudioDriver
*) arg
;
739 ALuint buffersreturned
= 0;
740 ALboolean bFinished
= AL_FALSE
;
741 while (driver
->stayAlive
) {
743 StackLock
l(driver
->musicMutex
, "musicMutex in PlayListManager()");
744 if (driver
->MusicPlaying
) {
746 alGetSourcei( driver
->MusicSource
, AL_SOURCE_STATE
, &state
);
747 if (checkALError("Unable to query music source state", "ERROR")) {
748 driver
->MusicPlaying
= false;
753 printMessage("OpenAL", "WARNING: Unhandled Music state", WHITE
);
754 printStatus("ERROR", YELLOW
);
755 driver
->MusicPlaying
= false;
759 printMessage("OPENAL", "Music in INITIAL State. AutoStarting\n", WHITE
);
760 for (int i
= 0; i
< MUSICBUFFERS
; i
++) {
761 driver
->MusicReader
->read_samples( ( short* ) driver
->music_memory
, ACM_BUFFERSIZE
>> 1 );
762 alBufferData( driver
->MusicBuffer
[i
], AL_FORMAT_STEREO16
,
763 driver
->music_memory
, ACM_BUFFERSIZE
,
764 driver
->MusicReader
->get_samplerate() );
766 alSourceQueueBuffers( driver
->MusicSource
, MUSICBUFFERS
, driver
->MusicBuffer
);
767 if (alIsSource( driver
->MusicSource
)) {
768 alSourcePlay( driver
->MusicSource
);
769 checkALError("Error playing music source", "ERROR");
771 bFinished
= AL_FALSE
;
775 printMessage("OpenAL", "WARNING: Buffer Underrun. AutoRestarting Stream Playback\n", WHITE
);
776 if (alIsSource( driver
->MusicSource
)) {
777 alSourcePlay( driver
->MusicSource
);
778 checkALError("Error playing music source", "ERROR");
785 alGetSourcei( driver
->MusicSource
, AL_BUFFERS_PROCESSED
, &processed
);
786 if (checkALError("Unable to query music source state", "ERROR")) {
787 driver
->MusicPlaying
= false;
791 buffersreturned
+= processed
;
794 alSourceUnqueueBuffers( driver
->MusicSource
, 1, &BufferID
);
795 if (checkALError("Unable to unqueue music buffers", "ERROR")) {
796 driver
->MusicPlaying
= false;
799 if (bFinished
== AL_FALSE
) {
800 int size
= ACM_BUFFERSIZE
;
801 int cnt
= driver
->MusicReader
->read_samples( ( short* ) driver
->music_memory
, ACM_BUFFERSIZE
>> 1 );
806 printMessage("OpenAL", "Playing Next Music\n", WHITE
);
807 core
->GetMusicMgr()->PlayNext();
808 if (driver
->MusicPlaying
) {
809 printMessage( "OpenAL", "Queuing New Music\n", WHITE
);
810 driver
->MusicReader
->read_samples( ( short* ) ( driver
->music_memory
+ ( cnt
*2 ) ), size
>> 1 );
811 bFinished
= AL_FALSE
;
813 printMessage( "OpenAL", "No Other Music to play\n", WHITE
);
814 memset( driver
->music_memory
+ ( cnt
* 2 ), 0, size
);
815 driver
->MusicPlaying
= false;
819 alBufferData( BufferID
, AL_FORMAT_STEREO16
, driver
->music_memory
, ACM_BUFFERSIZE
, driver
->MusicReader
->get_samplerate() );
820 if (checkALError("Unable to buffer music data", "ERROR")) {
821 driver
->MusicPlaying
= false;
824 alSourceQueueBuffers( driver
->MusicSource
, 1, &BufferID
);
825 if (checkALError("Unable to queue music buffers", "ERROR")) {
826 driver
->MusicPlaying
= false;
838 //This one is used for movies, might be useful for others ?
839 void OpenALAudioDriver::QueueBuffer(int stream
, unsigned short bits
,
840 int channels
, short* memory
,
841 int size
, int samplerate
)
845 alGenBuffers(1, &Buffer
);
846 if (checkALError("Unable to create buffer", "ERROR")) {
850 alBufferData(Buffer
, GetFormatEnum(channels
, bits
), memory
, size
, samplerate
);
851 if (checkALError("Unable to buffer data", "ERROR")) {
855 streams
[stream
].delete_buffers
= true;
856 streams
[stream
].ClearProcessedBuffers();
858 alSourceQueueBuffers(streams
[stream
].Source
, 1, &Buffer
);
859 if (checkALError("Unable to queue buffer", "ERROR")) {
864 alGetSourcei(streams
[stream
].Source
, AL_SOURCE_STATE
, &state
);
865 if (checkALError("Unable to query source state", "ERROR")) {
869 if (state
!= AL_PLAYING
) {
870 alSourcePlay(streams
[stream
].Source
);
871 checkALError("Unable to play source", "ERROR");
877 #include "plugindef.h"
879 GEMRB_PLUGIN(0x27DD67E0, "OpenAL Audio Driver")
880 PLUGIN_CLASS(IE_AUDIO_CLASS_ID
, OpenALAudioDriver
)