aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llaudio/llaudioengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llaudio/llaudioengine.cpp')
-rw-r--r--linden/indra/llaudio/llaudioengine.cpp1801
1 files changed, 1801 insertions, 0 deletions
diff --git a/linden/indra/llaudio/llaudioengine.cpp b/linden/indra/llaudio/llaudioengine.cpp
new file mode 100644
index 0000000..bed791a
--- /dev/null
+++ b/linden/indra/llaudio/llaudioengine.cpp
@@ -0,0 +1,1801 @@
1 /**
2 * @file audioengine.cpp
3 * @brief implementation of LLAudioEngine class abstracting the Open
4 * AL audio support
5 *
6 * $LicenseInfo:firstyear=2000&license=viewergpl$
7 *
8 * Copyright (c) 2000-2009, Linden Research, Inc.
9 *
10 * Second Life Viewer Source Code
11 * The source code in this file ("Source Code") is provided by Linden Lab
12 * to you under the terms of the GNU General Public License, version 2.0
13 * ("GPL"), unless you have obtained a separate licensing agreement
14 * ("Other License"), formally executed by you and Linden Lab. Terms of
15 * the GPL can be found in doc/GPL-license.txt in this distribution, or
16 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
17 *
18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
23 *
24 * By copying, modifying or distributing this software, you acknowledge
25 * that you have read and understood your obligations described above,
26 * and agree to abide by those obligations.
27 *
28 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30 * COMPLETENESS OR PERFORMANCE.
31 * $/LicenseInfo$
32 */
33
34#include <time.h>
35
36#include "linden_common.h"
37
38#include "llaudioengine.h"
39#include "llstreamingaudio.h"
40
41#include "llerror.h"
42#include "llmath.h"
43
44#include "sound_ids.h" // temporary hack for min/max distances
45
46#include "llvfs.h"
47#include "lldir.h"
48#include "llaudiodecodemgr.h"
49#include "llassetstorage.h"
50
51
52// necessary for grabbing sounds from sim (implemented in viewer)
53extern void request_sound(const LLUUID &sound_guid);
54
55LLAudioEngine* gAudiop = NULL;
56
57
58//
59// LLAudioEngine implementation
60//
61
62
63LLAudioEngine::LLAudioEngine()
64{
65 setDefaults();
66}
67
68
69LLAudioEngine::~LLAudioEngine()
70{
71}
72
73LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl()
74{
75 return mStreamingAudioImpl;
76}
77
78void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl)
79{
80 mStreamingAudioImpl = impl;
81}
82
83void LLAudioEngine::setDefaults()
84{
85 mMaxWindGain = 1.f;
86
87 mListenerp = NULL;
88
89 mMuted = false;
90 mUserData = NULL;
91
92 mLastStatus = 0;
93
94 mNumChannels = 0;
95 mEnableWind = false;
96
97 S32 i;
98 for (i = 0; i < MAX_CHANNELS; i++)
99 {
100 mChannels[i] = NULL;
101 }
102 for (i = 0; i < MAX_BUFFERS; i++)
103 {
104 mBuffers[i] = NULL;
105 }
106
107 mMasterGain = 1.f;
108 mInternalGain = 0.f;
109 mNextWindUpdate = 0.f;
110
111 mStreamingAudioImpl = NULL;
112
113 for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++)
114 mSecondaryGain[i] = 1.0f;
115}
116
117
118bool LLAudioEngine::init(const S32 num_channels, void* userdata)
119{
120 setDefaults();
121
122 mNumChannels = num_channels;
123 mUserData = userdata;
124
125 allocateListener();
126
127 // Initialize the decode manager
128 gAudioDecodeMgrp = new LLAudioDecodeMgr;
129
130 llinfos << "LLAudioEngine::init() AudioEngine successfully initialized" << llendl;
131
132 return true;
133}
134
135
136void LLAudioEngine::shutdown()
137{
138 // Clean up decode manager
139 delete gAudioDecodeMgrp;
140 gAudioDecodeMgrp = NULL;
141
142 // Clean up wind source
143 cleanupWind();
144
145 // Clean up audio sources
146 source_map::iterator iter_src;
147 for (iter_src = mAllSources.begin(); iter_src != mAllSources.end(); iter_src++)
148 {
149 delete iter_src->second;
150 }
151
152
153 // Clean up audio data
154 data_map::iterator iter_data;
155 for (iter_data = mAllData.begin(); iter_data != mAllData.end(); iter_data++)
156 {
157 delete iter_data->second;
158 }
159
160
161 // Clean up channels
162 S32 i;
163 for (i = 0; i < MAX_CHANNELS; i++)
164 {
165 delete mChannels[i];
166 mChannels[i] = NULL;
167 }
168
169 // Clean up buffers
170 for (i = 0; i < MAX_BUFFERS; i++)
171 {
172 delete mBuffers[i];
173 mBuffers[i] = NULL;
174 }
175}
176
177
178// virtual
179void LLAudioEngine::startInternetStream(const std::string& url)
180{
181 if (mStreamingAudioImpl)
182 mStreamingAudioImpl->start(url);
183}
184
185
186// virtual
187void LLAudioEngine::stopInternetStream()
188{
189 if (mStreamingAudioImpl)
190 mStreamingAudioImpl->stop();
191}
192
193// virtual
194void LLAudioEngine::pauseInternetStream(int pause)
195{
196 if (mStreamingAudioImpl)
197 mStreamingAudioImpl->pause(pause);
198}
199
200// virtual
201void LLAudioEngine::updateInternetStream()
202{
203 if (mStreamingAudioImpl)
204 mStreamingAudioImpl->update();
205}
206
207// virtual
208int LLAudioEngine::isInternetStreamPlaying()
209{
210 if (mStreamingAudioImpl)
211 return mStreamingAudioImpl->isPlaying();
212
213 return 0; // Stopped
214}
215
216
217// virtual
218void LLAudioEngine::setInternetStreamGain(F32 vol)
219{
220 if (mStreamingAudioImpl)
221 mStreamingAudioImpl->setGain(vol);
222}
223
224// virtual
225std::string LLAudioEngine::getInternetStreamURL()
226{
227 if (mStreamingAudioImpl)
228 return mStreamingAudioImpl->getURL();
229 else return std::string();
230}
231
232
233void LLAudioEngine::updateChannels()
234{
235 S32 i;
236 for (i = 0; i < MAX_CHANNELS; i++)
237 {
238 if (mChannels[i])
239 {
240 mChannels[i]->updateBuffer();
241 mChannels[i]->update3DPosition();
242 mChannels[i]->updateLoop();
243 }
244 }
245}
246
247static const F32 default_max_decode_time = .002f; // 2 ms
248void LLAudioEngine::idle(F32 max_decode_time)
249{
250 if (max_decode_time <= 0.f)
251 {
252 max_decode_time = default_max_decode_time;
253 }
254
255 // "Update" all of our audio sources, clean up dead ones.
256 // Primarily does position updating, cleanup of unused audio sources.
257 // Also does regeneration of the current priority of each audio source.
258
259 S32 i;
260 for (i = 0; i < MAX_BUFFERS; i++)
261 {
262 if (mBuffers[i])
263 {
264 mBuffers[i]->mInUse = false;
265 }
266 }
267
268 F32 max_priority = -1.f;
269 LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel
270 source_map::iterator iter;
271 for (iter = mAllSources.begin(); iter != mAllSources.end();)
272 {
273 LLAudioSource *sourcep = iter->second;
274
275 // Update this source
276 sourcep->update();
277 sourcep->updatePriority();
278
279 if (sourcep->isDone())
280 {
281 // The source is done playing, clean it up.
282 delete sourcep;
283 mAllSources.erase(iter++);
284 continue;
285 }
286
287 if (sourcep->isMuted())
288 {
289 ++iter;
290 continue;
291 }
292
293 if (!sourcep->getChannel() && sourcep->getCurrentBuffer())
294 {
295 // We could potentially play this sound if its priority is high enough.
296 if (sourcep->getPriority() > max_priority)
297 {
298 max_priority = sourcep->getPriority();
299 max_sourcep = sourcep;
300 }
301 }
302
303 // Move on to the next source
304 iter++;
305 }
306
307 // Now, do priority-based organization of audio sources.
308 // All channels used, check priorities.
309 // Find channel with lowest priority
310 if (max_sourcep)
311 {
312 LLAudioChannel *channelp = getFreeChannel(max_priority);
313 if (channelp)
314 {
315 //llinfos << "Replacing source in channel due to priority!" << llendl;
316 max_sourcep->setChannel(channelp);
317 channelp->setSource(max_sourcep);
318 if (max_sourcep->isSyncSlave())
319 {
320 // A sync slave, it doesn't start playing until it's synced up with the master.
321 // Flag this channel as waiting for sync, and return true.
322 channelp->setWaiting(true);
323 }
324 else
325 {
326 channelp->setWaiting(false);
327 if (channelp->mCurrentBufferp)
328 {
329 channelp->play();
330 }
331 }
332 }
333 }
334
335
336 // Do this BEFORE we update the channels
337 // Update the channels to sync up with any changes that the source made,
338 // such as changing what sound was playing.
339 updateChannels();
340
341 // Update queued sounds (switch to next queued data if the current has finished playing)
342 for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
343 {
344 // This is lame, instead of this I could actually iterate through all the sources
345 // attached to each channel, since only those with active channels
346 // can have anything interesting happen with their queue? (Maybe not true)
347 LLAudioSource *sourcep = iter->second;
348 if (!sourcep->mQueuedDatap || sourcep->isMuted())
349 {
350 // Muted, or nothing queued, so we don't care.
351 continue;
352 }
353
354 LLAudioChannel *channelp = sourcep->getChannel();
355 if (!channelp)
356 {
357 // This sound isn't playing, so we just process move the queue
358 sourcep->mCurrentDatap = sourcep->mQueuedDatap;
359 sourcep->mQueuedDatap = NULL;
360
361 // Reset the timer so the source doesn't die.
362 sourcep->mAgeTimer.reset();
363 // Make sure we have the buffer set up if we just decoded the data
364 if (sourcep->mCurrentDatap)
365 {
366 updateBufferForData(sourcep->mCurrentDatap);
367 }
368
369 // Actually play the associated data.
370 sourcep->setupChannel();
371 channelp = sourcep->getChannel();
372 if (channelp)
373 {
374 channelp->updateBuffer();
375 sourcep->getChannel()->play();
376 }
377 continue;
378 }
379 else
380 {
381 // Check to see if the current sound is done playing, or looped.
382 if (!channelp->isPlaying())
383 {
384 sourcep->mCurrentDatap = sourcep->mQueuedDatap;
385 sourcep->mQueuedDatap = NULL;
386
387 // Reset the timer so the source doesn't die.
388 sourcep->mAgeTimer.reset();
389
390 // Make sure we have the buffer set up if we just decoded the data
391 if (sourcep->mCurrentDatap)
392 {
393 updateBufferForData(sourcep->mCurrentDatap);
394 }
395
396 // Actually play the associated data.
397 sourcep->setupChannel();
398 channelp->updateBuffer();
399 sourcep->getChannel()->play();
400 }
401 else if (sourcep->isLoop())
402 {
403 // It's a loop, we need to check and see if we're done with it.
404 if (channelp->mLoopedThisFrame)
405 {
406 sourcep->mCurrentDatap = sourcep->mQueuedDatap;
407 sourcep->mQueuedDatap = NULL;
408
409 // Actually, should do a time sync so if we're a loop master/slave
410 // we don't drift away.
411 sourcep->setupChannel();
412 sourcep->getChannel()->play();
413 }
414 }
415 }
416 }
417
418 // Lame, update the channels AGAIN.
419 // Update the channels to sync up with any changes that the source made,
420 // such as changing what sound was playing.
421 updateChannels();
422
423 // Hack! For now, just use a global sync master;
424 LLAudioSource *sync_masterp = NULL;
425 LLAudioChannel *master_channelp = NULL;
426 F32 max_sm_priority = -1.f;
427 for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
428 {
429 LLAudioSource *sourcep = iter->second;
430 if (sourcep->isMuted())
431 {
432 continue;
433 }
434 if (sourcep->isSyncMaster())
435 {
436 if (sourcep->getPriority() > max_sm_priority)
437 {
438 sync_masterp = sourcep;
439 master_channelp = sync_masterp->getChannel();
440 max_sm_priority = sourcep->getPriority();
441 }
442 }
443 }
444
445 if (master_channelp && master_channelp->mLoopedThisFrame)
446 {
447 // Synchronize loop slaves with their masters
448 // Update queued sounds (switch to next queued data if the current has finished playing)
449 for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
450 {
451 LLAudioSource *sourcep = iter->second;
452
453 if (!sourcep->isSyncSlave())
454 {
455 // Not a loop slave, we don't need to do anything
456 continue;
457 }
458
459 LLAudioChannel *channelp = sourcep->getChannel();
460 if (!channelp)
461 {
462 // Not playing, don't need to bother.
463 continue;
464 }
465
466 if (!channelp->isPlaying())
467 {
468 // Now we need to check if our loop master has just looped, and
469 // start playback if that's the case.
470 if (sync_masterp->getChannel())
471 {
472 channelp->playSynced(master_channelp);
473 channelp->setWaiting(false);
474 }
475 }
476 }
477 }
478
479 // Sync up everything that the audio engine needs done.
480 commitDeferredChanges();
481
482 // Flush unused buffers that are stale enough
483 for (i = 0; i < MAX_BUFFERS; i++)
484 {
485 if (mBuffers[i])
486 {
487 if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f)
488 {
489 //llinfos << "Flushing unused buffer!" << llendl;
490 mBuffers[i]->mAudioDatap->mBufferp = NULL;
491 delete mBuffers[i];
492 mBuffers[i] = NULL;
493 }
494 }
495 }
496
497
498 // Clear all of the looped flags for the channels
499 for (i = 0; i < MAX_CHANNELS; i++)
500 {
501 if (mChannels[i])
502 {
503 mChannels[i]->mLoopedThisFrame = false;
504 }
505 }
506
507 // Decode audio files
508 gAudioDecodeMgrp->processQueue(max_decode_time);
509
510 // Call this every frame, just in case we somehow
511 // missed picking it up in all the places that can add
512 // or request new data.
513 startNextTransfer();
514
515 updateInternetStream();
516}
517
518
519
520bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid)
521{
522 if (!adp)
523 {
524 return false;
525 }
526
527 // Update the audio buffer first - load a sound if we have it.
528 // Note that this could potentially cause us to waste time updating buffers
529 // for sounds that actually aren't playing, although this should be mitigated
530 // by the fact that we limit the number of buffers, and we flush buffers based
531 // on priority.
532 if (!adp->getBuffer())
533 {
534 if (adp->hasDecodedData())
535 {
536 return adp->load();
537 }
538 else if (adp->hasLocalData())
539 {
540 if (audio_uuid.notNull())
541 {
542 gAudioDecodeMgrp->addDecodeRequest(audio_uuid);
543 }
544 }
545 else
546 {
547 return false;
548 }
549 }
550 return true;
551}
552
553
554void LLAudioEngine::enableWind(bool enable)
555{
556 if (enable && (!mEnableWind))
557 {
558 initWind();
559 mEnableWind = enable;
560 }
561 else if (mEnableWind && (!enable))
562 {
563 mEnableWind = enable;
564 cleanupWind();
565 }
566}
567
568
569LLAudioBuffer * LLAudioEngine::getFreeBuffer()
570{
571 static clock_t last_info = 0;
572 static bool spamming = FALSE;
573
574 S32 i;
575 for (i = 0; i < MAX_BUFFERS; i++)
576 {
577 if (!mBuffers[i])
578 {
579 mBuffers[i] = createBuffer();
580 return mBuffers[i];
581 }
582 }
583
584
585 // Grab the oldest unused buffer
586 F32 max_age = -1.f;
587 S32 buffer_id = -1;
588 for (i = 0; i < MAX_BUFFERS; i++)
589 {
590 if (mBuffers[i])
591 {
592 if (!mBuffers[i]->mInUse)
593 {
594 if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age)
595 {
596 max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32();
597 buffer_id = i;
598 }
599 }
600 }
601 }
602
603 if (buffer_id >= 0)
604 {
605 if (clock() - last_info > CLOCKS_PER_SEC)
606 {
607 // Do not spam us with such messages...
608 llinfos << "Taking over unused buffer " << buffer_id << llendl;
609 last_info = clock();
610 }
611 else if (!spamming)
612 {
613 // ... but warn us *once* when the buffer freeing frequency is abnormal.
614 llwarns << "Excessive buffer freeing frequency, info messages throttled." << llendl;
615 spamming = true;
616 }
617 mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL;
618 delete mBuffers[buffer_id];
619 mBuffers[buffer_id] = createBuffer();
620 return mBuffers[buffer_id];
621 }
622 return NULL;
623}
624
625
626LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
627{
628 S32 i;
629 for (i = 0; i < mNumChannels; i++)
630 {
631 if (!mChannels[i])
632 {
633 // No channel allocated here, use it.
634 mChannels[i] = createChannel();
635 return mChannels[i];
636 }
637 else
638 {
639 // Channel is allocated but not playing right now, use it.
640 if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting())
641 {
642 mChannels[i]->cleanup();
643 if (mChannels[i]->getSource())
644 {
645 mChannels[i]->getSource()->setChannel(NULL);
646 }
647 return mChannels[i];
648 }
649 }
650 }
651
652 // All channels used, check priorities.
653 // Find channel with lowest priority and see if we want to replace it.
654 F32 min_priority = 10000.f;
655 LLAudioChannel *min_channelp = NULL;
656
657 for (i = 0; i < mNumChannels; i++)
658 {
659 LLAudioChannel *channelp = mChannels[i];
660 LLAudioSource *sourcep = channelp->getSource();
661 if (sourcep && sourcep->getPriority() < min_priority)
662 {
663 min_channelp = channelp;
664 min_priority = sourcep->getPriority();
665 }
666 }
667
668 if (min_priority > priority || !min_channelp)
669 {
670 // All playing channels have higher priority, return.
671 return NULL;
672 }
673
674 // Flush the minimum priority channel, and return it.
675 min_channelp->cleanup();
676 min_channelp->getSource()->setChannel(NULL);
677 return min_channelp;
678}
679
680
681void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp)
682{
683 S32 i;
684 for (i = 0; i < MAX_BUFFERS; i++)
685 {
686 if (mBuffers[i] == bufferp)
687 {
688 delete mBuffers[i];
689 mBuffers[i] = NULL;
690 }
691 }
692}
693
694
695bool LLAudioEngine::preloadSound(const LLUUID &uuid)
696{
697 gAudiop->getAudioData(uuid); // We don't care about the return value, this is just to make sure
698 // that we have an entry, which will mean that the audio engine knows about this
699
700 if (gAudioDecodeMgrp->addDecodeRequest(uuid))
701 {
702 // This means that we do have a local copy, and we're working on decoding it.
703 return true;
704 }
705
706 // At some point we need to have the audio/asset system check the static VFS
707 // before it goes off and fetches stuff from the server.
708 //llwarns << "Used internal preload for non-local sound" << llendl;
709 return false;
710}
711
712
713bool LLAudioEngine::isWindEnabled()
714{
715 return mEnableWind;
716}
717
718
719void LLAudioEngine::setMuted(bool muted)
720{
721 if (muted != mMuted)
722 {
723 mMuted = muted;
724 setMasterGain(mMasterGain);
725 }
726 enableWind(!mMuted);
727}
728
729void LLAudioEngine::setMasterGain(const F32 gain)
730{
731 mMasterGain = gain;
732 F32 internal_gain = getMuted() ? 0.f : gain;
733 if (internal_gain != mInternalGain)
734 {
735 mInternalGain = internal_gain;
736 setInternalGain(mInternalGain);
737 }
738}
739
740F32 LLAudioEngine::getMasterGain()
741{
742 return mMasterGain;
743}
744
745void LLAudioEngine::setSecondaryGain(S32 type, F32 gain)
746{
747 llassert(type < LLAudioEngine::AUDIO_TYPE_COUNT);
748
749 mSecondaryGain[type] = gain;
750}
751
752F32 LLAudioEngine::getSecondaryGain(S32 type)
753{
754 return mSecondaryGain[type];
755}
756
757F32 LLAudioEngine::getInternetStreamGain()
758{
759 if (mStreamingAudioImpl)
760 return mStreamingAudioImpl->getGain();
761 else
762 return 1.0f;
763}
764
765void LLAudioEngine::setMaxWindGain(F32 gain)
766{
767 mMaxWindGain = gain;
768}
769
770
771F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec)
772{
773 F64 gain = 0.0;
774
775 gain = wind_vec.magVec();
776
777 if (gain)
778 {
779 if (gain > 20)
780 {
781 gain = 20;
782 }
783 gain = gain/20.0;
784 }
785
786 return (gain);
787}
788
789
790F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec)
791{
792 LLVector3 listen_right;
793 F64 theta;
794
795 // Wind frame is in listener-relative coordinates
796 LLVector3 norm_wind = wind_vec;
797 norm_wind.normVec();
798 listen_right.setVec(1.0,0.0,0.0);
799
800 // measure angle between wind vec and listener right axis (on 0,PI)
801 theta = acos(norm_wind * listen_right);
802
803 // put it on 0, 1
804 theta /= F_PI;
805
806 // put it on [0, 0.5, 0]
807 if (theta > 0.5) theta = 1.0-theta;
808 if (theta < 0) theta = 0;
809
810 return (theta);
811}
812
813
814F64 LLAudioEngine::mapWindVecToPan(LLVector3 wind_vec)
815{
816 LLVector3 listen_right;
817 F64 theta;
818
819 // Wind frame is in listener-relative coordinates
820 listen_right.setVec(1.0,0.0,0.0);
821
822 LLVector3 norm_wind = wind_vec;
823 norm_wind.normVec();
824
825 // measure angle between wind vec and listener right axis (on 0,PI)
826 theta = acos(norm_wind * listen_right);
827
828 // put it on 0, 1
829 theta /= F_PI;
830
831 return (theta);
832}
833
834
835void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain,
836 const S32 type, const LLVector3d &pos_global)
837{
838 // Create a new source (since this can't be associated with an existing source.
839 //llinfos << "Localized: " << audio_uuid << llendl;
840
841 if (mMuted)
842 {
843 return;
844 }
845
846 LLUUID source_id;
847 source_id.generate();
848
849 LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type);
850 gAudiop->addAudioSource(asp);
851 if (pos_global.isExactlyZero())
852 {
853 asp->setAmbient(true);
854 }
855 else
856 {
857 asp->setPositionGlobal(pos_global);
858 }
859 asp->updatePriority();
860 asp->play(audio_uuid);
861}
862
863
864void LLAudioEngine::setListenerPos(LLVector3 aVec)
865{
866 mListenerp->setPosition(aVec);
867}
868
869
870LLVector3 LLAudioEngine::getListenerPos()
871{
872 if (mListenerp)
873 {
874 return(mListenerp->getPosition());
875 }
876 else
877 {
878 return(LLVector3::zero);
879 }
880}
881
882
883void LLAudioEngine::setListenerVelocity(LLVector3 aVec)
884{
885 mListenerp->setVelocity(aVec);
886}
887
888
889void LLAudioEngine::translateListener(LLVector3 aVec)
890{
891 mListenerp->translate(aVec);
892}
893
894
895void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at)
896{
897 mListenerp->orient(up, at);
898}
899
900
901void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at)
902{
903 mListenerp->set(pos,vel,up,at);
904}
905
906
907void LLAudioEngine::setDopplerFactor(F32 factor)
908{
909 if (mListenerp)
910 {
911 mListenerp->setDopplerFactor(factor);
912 }
913}
914
915
916F32 LLAudioEngine::getDopplerFactor()
917{
918 if (mListenerp)
919 {
920 return mListenerp->getDopplerFactor();
921 }
922 else
923 {
924 return 0.f;
925 }
926}
927
928
929void LLAudioEngine::setRolloffFactor(F32 factor)
930{
931 if (mListenerp)
932 {
933 mListenerp->setRolloffFactor(factor);
934 }
935}
936
937
938F32 LLAudioEngine::getRolloffFactor()
939{
940 if (mListenerp)
941 {
942 return mListenerp->getRolloffFactor();
943 }
944 else
945 {
946 return 0.f;
947 }
948}
949
950
951void LLAudioEngine::commitDeferredChanges()
952{
953 mListenerp->commitDeferredChanges();
954}
955
956
957LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id)
958{
959 source_map::iterator iter;
960 iter = mAllSources.find(source_id);
961
962 if (iter == mAllSources.end())
963 {
964 return NULL;
965 }
966 else
967 {
968 return iter->second;
969 }
970}
971
972
973LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid)
974{
975 data_map::iterator iter;
976 iter = mAllData.find(audio_uuid);
977 if (iter == mAllData.end())
978 {
979 // Create the new audio data
980 LLAudioData *adp = new LLAudioData(audio_uuid);
981 mAllData[audio_uuid] = adp;
982 return adp;
983 }
984 else
985 {
986 return iter->second;
987 }
988}
989
990void LLAudioEngine::addAudioSource(LLAudioSource *asp)
991{
992 mAllSources[asp->getID()] = asp;
993}
994
995
996void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
997{
998 source_map::iterator iter;
999 iter = mAllSources.find(asp->getID());
1000 if (iter == mAllSources.end())
1001 {
1002 llwarns << "Cleaning up unknown audio source!" << llendl;
1003 return;
1004 }
1005 delete asp;
1006 mAllSources.erase(iter);
1007}
1008
1009
1010bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid)
1011{
1012 std::string uuid_str;
1013 uuid.toString(uuid_str);
1014
1015 std::string wav_path;
1016 wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str);
1017 wav_path += ".dsf";
1018
1019 if (gDirUtilp->fileExists(wav_path))
1020 {
1021 return true;
1022 }
1023 else
1024 {
1025 return false;
1026 }
1027}
1028
1029
1030bool LLAudioEngine::hasLocalFile(const LLUUID &uuid)
1031{
1032 // See if it's in the VFS.
1033 return gVFS->getExists(uuid, LLAssetType::AT_SOUND);
1034}
1035
1036
1037void LLAudioEngine::startNextTransfer()
1038{
1039 //llinfos << "LLAudioEngine::startNextTransfer()" << llendl;
1040 if (mCurrentTransfer.notNull() || getMuted())
1041 {
1042 //llinfos << "Transfer in progress, aborting" << llendl;
1043 return;
1044 }
1045
1046 // Get the ID for the next asset that we want to transfer.
1047 // Pick one in the following order:
1048 LLUUID asset_id;
1049 S32 i;
1050 LLAudioSource *asp = NULL;
1051 LLAudioData *adp = NULL;
1052 data_map::iterator data_iter;
1053
1054 // Check all channels for currently playing sounds.
1055 F32 max_pri = -1.f;
1056 for (i = 0; i < MAX_CHANNELS; i++)
1057 {
1058 if (!mChannels[i])
1059 {
1060 continue;
1061 }
1062
1063 asp = mChannels[i]->getSource();
1064 if (!asp)
1065 {
1066 continue;
1067 }
1068 if (asp->getPriority() <= max_pri)
1069 {
1070 continue;
1071 }
1072
1073 if (asp->getPriority() <= max_pri)
1074 {
1075 continue;
1076 }
1077
1078 adp = asp->getCurrentData();
1079 if (!adp)
1080 {
1081 continue;
1082 }
1083
1084 if (!adp->hasLocalData() && adp->hasValidData())
1085 {
1086 asset_id = adp->getID();
1087 max_pri = asp->getPriority();
1088 }
1089 }
1090
1091 // Check all channels for currently queued sounds.
1092 if (asset_id.isNull())
1093 {
1094 max_pri = -1.f;
1095 for (i = 0; i < MAX_CHANNELS; i++)
1096 {
1097 if (!mChannels[i])
1098 {
1099 continue;
1100 }
1101
1102 LLAudioSource *asp;
1103 asp = mChannels[i]->getSource();
1104 if (!asp)
1105 {
1106 continue;
1107 }
1108
1109 if (asp->getPriority() <= max_pri)
1110 {
1111 continue;
1112 }
1113
1114 adp = asp->getQueuedData();
1115 if (!adp)
1116 {
1117 continue;
1118 }
1119
1120 if (!adp->hasLocalData() && adp->hasValidData())
1121 {
1122 asset_id = adp->getID();
1123 max_pri = asp->getPriority();
1124 }
1125 }
1126 }
1127
1128 // Check all live channels for other sounds (preloads).
1129 if (asset_id.isNull())
1130 {
1131 max_pri = -1.f;
1132 for (i = 0; i < MAX_CHANNELS; i++)
1133 {
1134 if (!mChannels[i])
1135 {
1136 continue;
1137 }
1138
1139 LLAudioSource *asp;
1140 asp = mChannels[i]->getSource();
1141 if (!asp)
1142 {
1143 continue;
1144 }
1145
1146 if (asp->getPriority() <= max_pri)
1147 {
1148 continue;
1149 }
1150
1151
1152 for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++)
1153 {
1154 LLAudioData *adp = data_iter->second;
1155 if (!adp)
1156 {
1157 continue;
1158 }
1159
1160 if (!adp->hasLocalData() && adp->hasValidData())
1161 {
1162 asset_id = adp->getID();
1163 max_pri = asp->getPriority();
1164 }
1165 }
1166 }
1167 }
1168
1169 // Check all sources
1170 if (asset_id.isNull())
1171 {
1172 max_pri = -1.f;
1173 source_map::iterator source_iter;
1174 for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++)
1175 {
1176 asp = source_iter->second;
1177 if (!asp)
1178 {
1179 continue;
1180 }
1181
1182 if (asp->getPriority() <= max_pri)
1183 {
1184 continue;
1185 }
1186
1187 adp = asp->getCurrentData();
1188 if (adp && !adp->hasLocalData() && adp->hasValidData())
1189 {
1190 asset_id = adp->getID();
1191 max_pri = asp->getPriority();
1192 continue;
1193 }
1194
1195 adp = asp->getQueuedData();
1196 if (adp && !adp->hasLocalData() && adp->hasValidData())
1197 {
1198 asset_id = adp->getID();
1199 max_pri = asp->getPriority();
1200 continue;
1201 }
1202
1203 for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++)
1204 {
1205 LLAudioData *adp = data_iter->second;
1206 if (!adp)
1207 {
1208 continue;
1209 }
1210
1211 if (!adp->hasLocalData() && adp->hasValidData())
1212 {
1213 asset_id = adp->getID();
1214 max_pri = asp->getPriority();
1215 break;
1216 }
1217 }
1218 }
1219 }
1220
1221 if (asset_id.notNull())
1222 {
1223 llinfos << "Getting asset data for: " << asset_id << llendl;
1224 gAudiop->mCurrentTransfer = asset_id;
1225 gAudiop->mCurrentTransferTimer.reset();
1226 gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND,
1227 assetCallback, NULL);
1228 }
1229 else
1230 {
1231 //llinfos << "No pending transfers?" << llendl;
1232 }
1233}
1234
1235
1236// static
1237void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status)
1238{
1239 if (result_code)
1240 {
1241 llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl;
1242 // Need to mark data as bad to avoid constant rerequests.
1243 LLAudioData *adp = gAudiop->getAudioData(uuid);
1244 if (adp)
1245 {
1246 adp->setHasValidData(false);
1247 adp->setHasLocalData(false);
1248 adp->setHasDecodedData(false);
1249 }
1250 }
1251 else
1252 {
1253 LLAudioData *adp = gAudiop->getAudioData(uuid);
1254 if (!adp)
1255 {
1256 // Should never happen
1257 llwarns << "Got asset callback without audio data for " << uuid << llendl;
1258 }
1259 else
1260 {
1261 adp->setHasValidData(true);
1262 adp->setHasLocalData(true);
1263 gAudioDecodeMgrp->addDecodeRequest(uuid);
1264 }
1265 }
1266 gAudiop->mCurrentTransfer = LLUUID::null;
1267 gAudiop->startNextTransfer();
1268}
1269
1270
1271//
1272// LLAudioSource implementation
1273//
1274
1275
1276LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 gain, const S32 type)
1277: mID(id),
1278 mOwnerID(owner_id),
1279 mPriority(0.f),
1280 mGain(gain),
1281 mSourceMuted(false),
1282 mAmbient(false),
1283 mLoop(false),
1284 mSyncMaster(false),
1285 mSyncSlave(false),
1286 mQueueSounds(false),
1287 mPlayedOnce(false),
1288 mType(type),
1289 mChannelp(NULL),
1290 mCurrentDatap(NULL),
1291 mQueuedDatap(NULL)
1292{
1293}
1294
1295
1296LLAudioSource::~LLAudioSource()
1297{
1298 if (mChannelp)
1299 {
1300 // Stop playback of this sound
1301 mChannelp->setSource(NULL);
1302 mChannelp = NULL;
1303 }
1304}
1305
1306
1307void LLAudioSource::setChannel(LLAudioChannel *channelp)
1308{
1309 if (channelp == mChannelp)
1310 {
1311 return;
1312 }
1313
1314 mChannelp = channelp;
1315}
1316
1317
1318void LLAudioSource::update()
1319{
1320 if (!getCurrentBuffer())
1321 {
1322 if (getCurrentData())
1323 {
1324 // Hack - try and load the sound. Will do this as a callback
1325 // on decode later.
1326 if (getCurrentData()->load())
1327 {
1328 play(getCurrentData()->getID());
1329 }
1330 }
1331 }
1332}
1333
1334void LLAudioSource::updatePriority()
1335{
1336 if (isAmbient())
1337 {
1338 mPriority = 1.f;
1339 }
1340 else if (isMuted())
1341 {
1342 mPriority = 0.f;
1343 }
1344 else
1345 {
1346 // Priority is based on distance
1347 LLVector3 dist_vec;
1348 dist_vec.setVec(getPositionGlobal());
1349 dist_vec -= gAudiop->getListenerPos();
1350 F32 dist_squared = llmax(1.f, dist_vec.magVecSquared());
1351
1352 mPriority = mGain / dist_squared;
1353 }
1354}
1355
1356bool LLAudioSource::setupChannel()
1357{
1358 LLAudioData *adp = getCurrentData();
1359
1360 if (!adp->getBuffer())
1361 {
1362 // We're not ready to play back the sound yet, so don't try and allocate a channel for it.
1363 //llwarns << "Aborting, no buffer" << llendl;
1364 return false;
1365 }
1366
1367
1368 if (!mChannelp)
1369 {
1370 // Update the priority, in case we need to push out another channel.
1371 updatePriority();
1372
1373 setChannel(gAudiop->getFreeChannel(getPriority()));
1374 }
1375
1376 if (!mChannelp)
1377 {
1378 // Ugh, we don't have any free channels.
1379 // Now we have to reprioritize.
1380 // For now, just don't play the sound.
1381 //llwarns << "Aborting, no free channels" << llendl;
1382 return false;
1383 }
1384
1385 mChannelp->setSource(this);
1386 return true;
1387}
1388
1389
1390bool LLAudioSource::play(const LLUUID &audio_uuid)
1391{
1392 // Special abuse of play(); don't play a sound, but kill it.
1393 if (audio_uuid.isNull())
1394 {
1395 if (getChannel())
1396 {
1397 getChannel()->setSource(NULL);
1398 setChannel(NULL);
1399 if (!isMuted())
1400 {
1401 mCurrentDatap = NULL;
1402 }
1403 }
1404 return false;
1405 }
1406
1407 // Reset our age timeout if someone attempts to play the source.
1408 mAgeTimer.reset();
1409
1410 LLAudioData *adp = gAudiop->getAudioData(audio_uuid);
1411 addAudioData(adp);
1412
1413 if (isMuted())
1414 {
1415 return false;
1416 }
1417
1418 bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid);
1419 if (!has_buffer)
1420 {
1421 // Don't bother trying to set up a channel or anything, we don't have an audio buffer.
1422 return false;
1423 }
1424
1425 if (!setupChannel())
1426 {
1427 return false;
1428 }
1429
1430 if (isSyncSlave())
1431 {
1432 // A sync slave, it doesn't start playing until it's synced up with the master.
1433 // Flag this channel as waiting for sync, and return true.
1434 getChannel()->setWaiting(true);
1435 return true;
1436 }
1437
1438 getChannel()->play();
1439 return true;
1440}
1441
1442
1443bool LLAudioSource::isDone() const
1444{
1445 const F32 MAX_AGE = 60.f;
1446 const F32 MAX_UNPLAYED_AGE = 15.f;
1447 const F32 MAX_MUTED_AGE = 11.f;
1448
1449 if (isLoop())
1450 {
1451 // Looped sources never die on their own.
1452 return false;
1453 }
1454
1455 if (hasPendingPreloads())
1456 {
1457 return false;
1458 }
1459
1460 if (mQueuedDatap)
1461 {
1462 // Don't kill this sound if we've got something queued up to play.
1463 return false;
1464 }
1465
1466 F32 elapsed = mAgeTimer.getElapsedTimeF32();
1467
1468 // This is a single-play source
1469 if (!mChannelp)
1470 {
1471 if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce)
1472 {
1473 // We don't have a channel assigned, and it's been
1474 // over 15 seconds since we tried to play it. Don't bother.
1475 //llinfos << "No channel assigned, source is done" << llendl;
1476 return true;
1477 }
1478 else
1479 {
1480 return false;
1481 }
1482 }
1483
1484 if (mChannelp->isPlaying())
1485 {
1486 if (elapsed > MAX_AGE)
1487 {
1488 // Arbitarily cut off non-looped sounds when they're old.
1489 return true;
1490 }
1491 else
1492 {
1493 // Sound is still playing and we haven't timed out, don't kill it.
1494 return false;
1495 }
1496 }
1497
1498 if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce)
1499 {
1500 // The sound isn't playing back after 15 seconds or we're already done playing it, kill it.
1501 return true;
1502 }
1503
1504 return false;
1505}
1506
1507
1508void LLAudioSource::addAudioData(LLAudioData *adp, const bool set_current)
1509{
1510 // Only handle a single piece of audio data associated with a source right now,
1511 // until I implement prefetch.
1512 if (set_current)
1513 {
1514 if (!mCurrentDatap)
1515 {
1516 mCurrentDatap = adp;
1517 if (mChannelp)
1518 {
1519 mChannelp->updateBuffer();
1520 mChannelp->play();
1521 }
1522
1523 // Make sure the audio engine knows that we want to request this sound.
1524 gAudiop->startNextTransfer();
1525 return;
1526 }
1527 else if (mQueueSounds)
1528 {
1529 // If we have current data, and we're queuing, put
1530 // the object onto the queue.
1531 if (mQueuedDatap)
1532 {
1533 // We only queue one sound at a time, and it's a FIFO.
1534 // Don't put it onto the queue.
1535 return;
1536 }
1537
1538 if (adp == mCurrentDatap && isLoop())
1539 {
1540 // No point in queueing the same sound if
1541 // we're looping.
1542 return;
1543 }
1544 mQueuedDatap = adp;
1545
1546 // Make sure the audio engine knows that we want to request this sound.
1547 gAudiop->startNextTransfer();
1548 }
1549 else
1550 {
1551 if (mCurrentDatap != adp)
1552 {
1553 // Right now, if we're currently playing this sound in a channel, we
1554 // update the buffer that the channel's associated with
1555 // and play it. This may not be the correct behavior.
1556 mCurrentDatap = adp;
1557 if (mChannelp)
1558 {
1559 mChannelp->updateBuffer();
1560 mChannelp->play();
1561 }
1562 // Make sure the audio engine knows that we want to request this sound.
1563 gAudiop->startNextTransfer();
1564 }
1565 }
1566 }
1567 else
1568 {
1569 // Add it to the preload list.
1570 mPreloadMap[adp->getID()] = adp;
1571 gAudiop->startNextTransfer();
1572 }
1573}
1574
1575
1576bool LLAudioSource::hasPendingPreloads() const
1577{
1578 // Check to see if we've got any preloads on deck for this source
1579 data_map::const_iterator iter;
1580 for (iter = mPreloadMap.begin(); iter != mPreloadMap.end(); iter++)
1581 {
1582 LLAudioData *adp = iter->second;
1583 // note: a bad UUID will forever be !hasDecodedData()
1584 // but also !hasValidData(), hence the check for hasValidData()
1585 if (!adp->hasDecodedData() && adp->hasValidData())
1586 {
1587 // This source is still waiting for a preload
1588 return true;
1589 }
1590 }
1591
1592 return false;
1593}
1594
1595
1596LLAudioData * LLAudioSource::getCurrentData()
1597{
1598 return mCurrentDatap;
1599}
1600
1601LLAudioData * LLAudioSource::getQueuedData()
1602{
1603 return mQueuedDatap;
1604}
1605
1606LLAudioBuffer * LLAudioSource::getCurrentBuffer()
1607{
1608 if (!mCurrentDatap)
1609 {
1610 return NULL;
1611 }
1612
1613 return mCurrentDatap->getBuffer();
1614}
1615
1616
1617
1618
1619//
1620// LLAudioChannel implementation
1621//
1622
1623
1624LLAudioChannel::LLAudioChannel() :
1625 mCurrentSourcep(NULL),
1626 mCurrentBufferp(NULL),
1627 mLoopedThisFrame(false),
1628 mWaiting(false),
1629 mSecondaryGain(1.0f)
1630{
1631}
1632
1633
1634LLAudioChannel::~LLAudioChannel()
1635{
1636 // Need to disconnect any sources which are using this channel.
1637 //llinfos << "Cleaning up audio channel" << llendl;
1638 if (mCurrentSourcep)
1639 {
1640 mCurrentSourcep->setChannel(NULL);
1641 }
1642 mCurrentBufferp = NULL;
1643}
1644
1645
1646void LLAudioChannel::setSource(LLAudioSource *sourcep)
1647{
1648 //llinfos << this << ": setSource(" << sourcep << ")" << llendl;
1649
1650 if (!sourcep)
1651 {
1652 // Clearing the source for this channel, don't need to do anything.
1653 //llinfos << "Clearing source for channel" << llendl;
1654 cleanup();
1655 mCurrentSourcep = NULL;
1656 mWaiting = false;
1657 return;
1658 }
1659
1660 if (sourcep == mCurrentSourcep)
1661 {
1662 // Don't reallocate the channel, this will make FMOD goofy.
1663 //llinfos << "Calling setSource with same source!" << llendl;
1664 }
1665
1666 mCurrentSourcep = sourcep;
1667
1668
1669 updateBuffer();
1670 update3DPosition();
1671}
1672
1673
1674bool LLAudioChannel::updateBuffer()
1675{
1676 if (!mCurrentSourcep)
1677 {
1678 // This channel isn't associated with any source, nothing
1679 // to be updated
1680 return false;
1681 }
1682
1683 // Initialize the channel's gain setting for this sound.
1684 if(gAudiop)
1685 {
1686 setSecondaryGain(gAudiop->getSecondaryGain(mCurrentSourcep->getType()));
1687 }
1688
1689 LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer();
1690 if (bufferp == mCurrentBufferp)
1691 {
1692 if (bufferp)
1693 {
1694 // The source hasn't changed what buffer it's playing
1695 bufferp->mLastUseTimer.reset();
1696 bufferp->mInUse = true;
1697 }
1698 return false;
1699 }
1700
1701 //
1702 // The source changed what buffer it's playing. We need to clean up
1703 // the existing channel
1704 //
1705 cleanup();
1706
1707 mCurrentBufferp = bufferp;
1708 if (bufferp)
1709 {
1710 bufferp->mLastUseTimer.reset();
1711 bufferp->mInUse = true;
1712 }
1713
1714 if (!mCurrentBufferp)
1715 {
1716 // There's no new buffer to be played, so we just abort.
1717 return false;
1718 }
1719
1720 return true;
1721}
1722
1723
1724
1725
1726//
1727// LLAudioData implementation
1728//
1729
1730
1731LLAudioData::LLAudioData(const LLUUID &uuid) :
1732 mID(uuid),
1733 mBufferp(NULL),
1734 mHasLocalData(false),
1735 mHasDecodedData(false),
1736 mHasValidData(true)
1737{
1738 if (uuid.isNull())
1739 {
1740 // This is a null sound.
1741 return;
1742 }
1743
1744 if (gAudiop && gAudiop->hasDecodedFile(uuid))
1745 {
1746 // Already have a decoded version, don't need to decode it.
1747 mHasLocalData = true;
1748 mHasDecodedData = true;
1749 }
1750 else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND))
1751 {
1752 mHasLocalData = true;
1753 }
1754}
1755
1756
1757bool LLAudioData::load()
1758{
1759 static clock_t last_info = 0;
1760
1761 // For now, just assume we're going to use one buffer per audiodata.
1762 if (mBufferp)
1763 {
1764 // We already have this sound in a buffer, don't do anything.
1765 llinfos << "Already have a buffer for this sound, don't bother loading!" << llendl;
1766 return true;
1767 }
1768
1769 mBufferp = gAudiop->getFreeBuffer();
1770 if (!mBufferp)
1771 {
1772 // No free buffers, abort.
1773 if (clock() - last_info > CLOCKS_PER_SEC) // Do not spam us with such messages
1774 {
1775 llinfos << "Not able to allocate a new audio buffer, aborting." << llendl;
1776 last_info = clock();
1777 }
1778 return false;
1779 }
1780
1781 std::string uuid_str;
1782 std::string wav_path;
1783 mID.toString(uuid_str);
1784 wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf";
1785
1786 if (!mBufferp->loadWAV(wav_path))
1787 {
1788 // Hrm. Right now, let's unset the buffer, since it's empty.
1789 gAudiop->cleanupBuffer(mBufferp);
1790 mBufferp = NULL;
1791
1792 // Maybe it was removed by another instance. Send it to the preload queue.
1793 gAudiop->preloadSound(mID);
1794
1795 return false;
1796 }
1797 mBufferp->mAudioDatap = this;
1798 return true;
1799}
1800
1801