audioengine.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 
00035 #include "audioengine.h"
00036 
00037 #include "llerror.h"
00038 #include "llmath.h"
00039 
00040 #include "sound_ids.h"  // temporary hack for min/max distances
00041 
00042 #include "llvfs.h"
00043 #include "lldir.h"
00044 #include "llaudiodecodemgr.h"
00045 #include "llassetstorage.h"
00046 
00047 // necessary for grabbing sounds from sim (implemented in viewer)       
00048 extern void request_sound(const LLUUID &sound_guid);
00049 
00050 LLAudioEngine* gAudiop = NULL;
00051 
00052 // Maximum amount of time we wait for a transfer to complete before starting
00053 // off another one.
00054 const F32 MAX_CURRENT_TRANSFER_TIME = 60.f;
00055 
00056 //
00057 // LLAudioEngine implementation
00058 //
00059 
00060 
00061 LLAudioEngine::LLAudioEngine()
00062 {
00063         setDefaults();
00064 }
00065 
00066 
00067 LLAudioEngine::~LLAudioEngine()
00068 {
00069 }
00070 
00071 
00072 void LLAudioEngine::setDefaults()
00073 {
00074         mMaxWindGain = 1.f;
00075 
00076         mListenerp = NULL;
00077 
00078         mMuted = FALSE;
00079         mUserData = NULL;
00080 
00081         mLastStatus = 0;
00082 
00083         mNumChannels = 0;
00084         mEnableWind = FALSE;
00085 
00086         S32 i;
00087         for (i = 0; i < MAX_CHANNELS; i++)
00088         {
00089                 mChannels[i] = NULL;
00090         }
00091         for (i = 0; i < MAX_BUFFERS; i++)
00092         {
00093                 mBuffers[i] = NULL;
00094         }       
00095 
00096         mMasterGain = 1.f;
00097         mInternetStreamGain = 0.125f;
00098         mNextWindUpdate = 0.f;
00099 }
00100 
00101 
00102 BOOL LLAudioEngine::init(const S32 num_channels, void* userdata)
00103 {
00104         setDefaults();
00105 
00106         mNumChannels = num_channels;
00107         mUserData = userdata;
00108         
00109         allocateListener();
00110 
00111         // Initialize the decode manager
00112         gAudioDecodeMgrp = new LLAudioDecodeMgr;
00113 
00114         return TRUE;
00115 }
00116 
00117 
00118 void LLAudioEngine::shutdown()
00119 {
00120         // Clean up decode manager
00121         delete gAudioDecodeMgrp;
00122         gAudioDecodeMgrp = NULL;
00123 
00124         // Clean up audio sources
00125         source_map::iterator iter_src;
00126         for (iter_src = mAllSources.begin(); iter_src != mAllSources.end(); iter_src++)
00127         {
00128                 delete iter_src->second;
00129         }
00130 
00131 
00132         // Clean up audio data
00133         data_map::iterator iter_data;
00134         for (iter_data = mAllData.begin(); iter_data != mAllData.end(); iter_data++)
00135         {
00136                 delete iter_data->second;
00137         }
00138 
00139 
00140         // Clean up channels
00141         S32 i;
00142         for (i = 0; i < MAX_CHANNELS; i++)
00143         {
00144                 if (mChannels[i])
00145                 {
00146                         delete mChannels[i];
00147                         mChannels[i] = NULL;
00148                 }
00149         }
00150 
00151         // Clean up buffers
00152         for (i = 0; i < MAX_BUFFERS; i++)
00153         {
00154                 if (mBuffers[i])
00155                 {
00156                         delete mBuffers[i];
00157                         mBuffers[i] = NULL;
00158                 }
00159         }
00160 }
00161 
00162 
00163 void LLAudioEngine::updateChannels()
00164 {
00165         S32 i;
00166         for (i = 0; i < MAX_CHANNELS; i++)
00167         {
00168                 if (mChannels[i])
00169                 {
00170                         mChannels[i]->updateBuffer();
00171                         mChannels[i]->update3DPosition();
00172                         mChannels[i]->updateLoop();
00173                 }
00174         }
00175 }
00176 
00177 static const F32 default_max_decode_time = .002f; // 2 ms
00178 void LLAudioEngine::idle(F32 max_decode_time)
00179 {
00180         if (max_decode_time <= 0.f)
00181         {
00182                 max_decode_time = default_max_decode_time;
00183         }
00184         
00185         // "Update" all of our audio sources, clean up dead ones.
00186         // Primarily does position updating, cleanup of unused audio sources.
00187         // Also does regeneration of the current priority of each audio source.
00188 
00189         if (getMuted())
00190         {
00191                 setInternalGain(0.f);
00192         }
00193         else
00194         {
00195                 setInternalGain(getMasterGain());
00196         }
00197 
00198         S32 i;
00199         for (i = 0; i < MAX_BUFFERS; i++)
00200         {
00201                 if (mBuffers[i])
00202                 {
00203                         mBuffers[i]->mInUse = FALSE;
00204                 }
00205         }
00206 
00207         F32 max_priority = -1.f;
00208         LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel
00209         source_map::iterator iter;
00210         for (iter = mAllSources.begin(); iter != mAllSources.end();)
00211         {
00212                 LLAudioSource *sourcep = iter->second;
00213 
00214                 // Update this source
00215                 sourcep->update();
00216                 sourcep->updatePriority();
00217 
00218                 if (sourcep->isDone())
00219                 {
00220                         // The source is done playing, clean it up.
00221                         delete sourcep;
00222                         mAllSources.erase(iter++);
00223                         continue;
00224                 }
00225 
00226                 if (!sourcep->getChannel() && sourcep->getCurrentBuffer())
00227                 {
00228                         // We could potentially play this sound if its priority is high enough.
00229                         if (sourcep->getPriority() > max_priority)
00230                         {
00231                                 max_priority = sourcep->getPriority();
00232                                 max_sourcep = sourcep;
00233                         }
00234                 }
00235 
00236                 // Move on to the next source
00237                 iter++;
00238         }
00239 
00240         // Now, do priority-based organization of audio sources.
00241         // All channels used, check priorities.
00242         // Find channel with lowest priority
00243         if (max_sourcep)
00244         {
00245                 LLAudioChannel *channelp = getFreeChannel(max_priority);
00246                 if (channelp)
00247                 {
00248                         //llinfos << "Replacing source in channel due to priority!" << llendl;
00249                         max_sourcep->setChannel(channelp);
00250                         channelp->setSource(max_sourcep);
00251                         if (max_sourcep->isSyncSlave())
00252                         {
00253                                 // A sync slave, it doesn't start playing until it's synced up with the master.
00254                                 // Flag this channel as waiting for sync, and return true.
00255                                 channelp->setWaiting(TRUE);
00256                         }
00257                         else
00258                         {
00259                                 channelp->setWaiting(FALSE);
00260                                 channelp->play();
00261                         }
00262                 }
00263         }
00264 
00265         
00266         // Do this BEFORE we update the channels
00267         // Update the channels to sync up with any changes that the source made,
00268         // such as changing what sound was playing.
00269         updateChannels();
00270 
00271         // Update queued sounds (switch to next queued data if the current has finished playing)
00272         for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
00273         {
00274                 // This is lame, instead of this I could actually iterate through all the sources
00275                 // attached to each channel, since only those with active channels
00276                 // can have anything interesting happen with their queue? (Maybe not true)
00277                 LLAudioSource *sourcep = iter->second;
00278                 if (!sourcep->mQueuedDatap)
00279                 {
00280                         // Nothing queued, so we don't care.
00281                         continue;
00282                 }
00283 
00284                 LLAudioChannel *channelp = sourcep->getChannel();
00285                 if (!channelp)
00286                 {
00287                         // This sound isn't playing, so we just process move the queue
00288                         sourcep->mCurrentDatap = sourcep->mQueuedDatap;
00289                         sourcep->mQueuedDatap = NULL;
00290 
00291                         // Reset the timer so the source doesn't die.
00292                         sourcep->mAgeTimer.reset();
00293                         // Make sure we have the buffer set up if we just decoded the data
00294                         if (sourcep->mCurrentDatap)
00295                         {
00296                                 updateBufferForData(sourcep->mCurrentDatap);
00297                         }
00298 
00299                         // Actually play the associated data.
00300                         sourcep->setupChannel();
00301                         channelp = sourcep->getChannel();
00302                         if (channelp)
00303                         {
00304                                 channelp->updateBuffer();
00305                                 sourcep->getChannel()->play();
00306                         }
00307                         continue;
00308                 }
00309                 else
00310                 {
00311                         // Check to see if the current sound is done playing, or looped.
00312                         if (!channelp->isPlaying())
00313                         {
00314                                 sourcep->mCurrentDatap = sourcep->mQueuedDatap;
00315                                 sourcep->mQueuedDatap = NULL;
00316 
00317                                 // Reset the timer so the source doesn't die.
00318                                 sourcep->mAgeTimer.reset();
00319 
00320                                 // Make sure we have the buffer set up if we just decoded the data
00321                                 if (sourcep->mCurrentDatap)
00322                                 {
00323                                         updateBufferForData(sourcep->mCurrentDatap);
00324                                 }
00325 
00326                                 // Actually play the associated data.
00327                                 sourcep->setupChannel();
00328                                 channelp->updateBuffer();
00329                                 sourcep->getChannel()->play();
00330                         }
00331                         else if (sourcep->isLoop())
00332                         {
00333                                 // It's a loop, we need to check and see if we're done with it.
00334                                 if (channelp->mLoopedThisFrame)
00335                                 {
00336                                         sourcep->mCurrentDatap = sourcep->mQueuedDatap;
00337                                         sourcep->mQueuedDatap = NULL;
00338 
00339                                         // Actually, should do a time sync so if we're a loop master/slave
00340                                         // we don't drift away.
00341                                         sourcep->setupChannel();
00342                                         sourcep->getChannel()->play();
00343                                 }
00344                         }
00345                 }
00346         }
00347 
00348         // Lame, update the channels AGAIN.
00349         // Update the channels to sync up with any changes that the source made,
00350         // such as changing what sound was playing.
00351         updateChannels();
00352         
00353         // Hack!  For now, just use a global sync master;
00354         LLAudioSource *sync_masterp = NULL;
00355         LLAudioChannel *master_channelp = NULL;
00356         F32 max_sm_priority = -1.f;
00357         for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
00358         {
00359                 LLAudioSource *sourcep = iter->second;
00360                 if (sourcep->isSyncMaster())
00361                 {
00362                         if (sourcep->getPriority() > max_sm_priority)
00363                         {
00364                                 sync_masterp = sourcep;
00365                                 master_channelp = sync_masterp->getChannel();
00366                                 max_sm_priority = sourcep->getPriority();
00367                         }
00368                 }
00369         }
00370 
00371         if (master_channelp && master_channelp->mLoopedThisFrame)
00372         {
00373                 // Synchronize loop slaves with their masters
00374                 // Update queued sounds (switch to next queued data if the current has finished playing)
00375                 for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
00376                 {
00377                         LLAudioSource *sourcep = iter->second;
00378 
00379                         if (!sourcep->isSyncSlave())
00380                         {
00381                                 // Not a loop slave, we don't need to do anything
00382                                 continue;
00383                         }
00384 
00385                         LLAudioChannel *channelp = sourcep->getChannel();
00386                         if (!channelp)
00387                         {
00388                                 // Not playing, don't need to bother.
00389                                 continue;
00390                         }
00391 
00392                         if (!channelp->isPlaying())
00393                         {
00394                                 // Now we need to check if our loop master has just looped, and
00395                                 // start playback if that's the case.
00396                                 if (sync_masterp->getChannel())
00397                                 {
00398                                         channelp->playSynced(master_channelp);
00399                                         channelp->setWaiting(FALSE);
00400                                 }
00401                         }
00402                 }
00403         }
00404 
00405         // Sync up everything that the audio engine needs done.
00406         commitDeferredChanges();
00407         
00408         // Flush unused buffers that are stale enough
00409         for (i = 0; i < MAX_BUFFERS; i++)
00410         {
00411                 if (mBuffers[i])
00412                 {
00413                         if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f)
00414                         {
00415                                 //llinfos << "Flushing unused buffer!" << llendl;
00416                                 mBuffers[i]->mAudioDatap->mBufferp = NULL;
00417                                 delete mBuffers[i];
00418                                 mBuffers[i] = NULL;
00419                         }
00420                 }
00421         }
00422 
00423 
00424         // Clear all of the looped flags for the channels
00425         for (i = 0; i < MAX_CHANNELS; i++)
00426         {
00427                 if (mChannels[i])
00428                 {
00429                         mChannels[i]->mLoopedThisFrame = FALSE;
00430                 }
00431         }
00432 
00433         // Decode audio files
00434         gAudioDecodeMgrp->processQueue(max_decode_time);
00435         
00436         // Call this every frame, just in case we somehow
00437         // missed picking it up in all the places that can add
00438         // or request new data.
00439         startNextTransfer();
00440 }
00441 
00442 BOOL LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid)
00443 {
00444         if (!adp)
00445         {
00446                 return FALSE;
00447         }
00448 
00449         // Update the audio buffer first - load a sound if we have it.
00450         // Note that this could potentially cause us to waste time updating buffers
00451         // for sounds that actually aren't playing, although this should be mitigated
00452         // by the fact that we limit the number of buffers, and we flush buffers based
00453         // on priority.
00454         if (!adp->getBuffer())
00455         {
00456                 if (adp->hasDecodedData())
00457                 {
00458                         adp->load();
00459                 }
00460                 else if (adp->hasLocalData())
00461                 {
00462                         if (audio_uuid.notNull())
00463                         {
00464                                 gAudioDecodeMgrp->addDecodeRequest(audio_uuid);
00465                         }
00466                 }
00467                 else
00468                 {
00469                         return FALSE;
00470                 }
00471         }
00472         return TRUE;
00473 }
00474 
00475 
00476 void LLAudioEngine::enableWind(BOOL enable)
00477 {
00478         if (enable && (!mEnableWind))
00479         {
00480                 initWind();
00481                 mEnableWind = enable;
00482         }
00483         else if (mEnableWind && (!enable))
00484         {
00485                 mEnableWind = enable;
00486                 cleanupWind();
00487         }
00488 }
00489 
00490 
00491 LLAudioBuffer *LLAudioEngine::getFreeBuffer()
00492 {
00493         S32 i;
00494         for (i = 0; i < MAX_BUFFERS; i++)
00495         {
00496                 if (!mBuffers[i])
00497                 {
00498                         mBuffers[i] = createBuffer();
00499                         return mBuffers[i];
00500                 }
00501         }
00502 
00503 
00504         // Grab the oldest unused buffer
00505         F32 max_age = -1.f;
00506         S32 buffer_id = -1;
00507         for (i = 0; i < MAX_BUFFERS; i++)
00508         {
00509                 if (mBuffers[i])
00510                 {
00511                         if (!mBuffers[i]->mInUse)
00512                         {
00513                                 if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age)
00514                                 {
00515                                         max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32();
00516                                         buffer_id = i;
00517                                 }
00518                         }
00519                 }
00520         }
00521 
00522         if (buffer_id >= 0)
00523         {
00524                 llinfos << "Taking over unused buffer " << buffer_id << llendl;
00525                 //llinfos << "Flushing unused buffer!" << llendl;
00526                 mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL;
00527                 delete mBuffers[buffer_id];
00528                 mBuffers[buffer_id] = createBuffer();
00529                 return mBuffers[buffer_id];
00530         }
00531         return NULL;
00532 }
00533 
00534 
00535 LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority)
00536 {
00537         S32 i;
00538         for (i = 0; i < mNumChannels; i++)
00539         {
00540                 if (!mChannels[i])
00541                 {
00542                         // No channel allocated here, use it.
00543                         mChannels[i] = createChannel();
00544                         return mChannels[i];
00545                 }
00546                 else
00547                 {
00548                         // Channel is allocated but not playing right now, use it.
00549                         if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting())
00550                         {
00551                                 mChannels[i]->cleanup();
00552                                 if (mChannels[i]->getSource())
00553                                 {
00554                                         mChannels[i]->getSource()->setChannel(NULL);
00555                                 }
00556                                 return mChannels[i];
00557                         }
00558                 }
00559         }
00560 
00561         // All channels used, check priorities.
00562         // Find channel with lowest priority and see if we want to replace it.
00563         F32 min_priority = 10000.f;
00564         LLAudioChannel *min_channelp = NULL;
00565 
00566         for (i = 0; i < mNumChannels; i++)
00567         {
00568                 LLAudioChannel *channelp = mChannels[i];
00569                 LLAudioSource *sourcep = channelp->getSource();
00570                 if (sourcep->getPriority() < min_priority)
00571                 {
00572                         min_channelp = channelp;
00573                         min_priority = sourcep->getPriority();
00574                 }
00575         }
00576 
00577         if (min_priority > priority || !min_channelp)
00578         {
00579                 // All playing channels have higher priority, return.
00580                 return NULL;
00581         }
00582 
00583         // Flush the minimum priority channel, and return it.
00584         min_channelp->cleanup();
00585         min_channelp->getSource()->setChannel(NULL);
00586         return min_channelp;
00587 }
00588 
00589 
00590 void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp)
00591 {
00592         S32 i;
00593         for (i = 0; i < MAX_BUFFERS; i++)
00594         {
00595                 if (mBuffers[i] == bufferp)
00596                 {
00597                         delete mBuffers[i];
00598                         mBuffers[i] = NULL;
00599                 }
00600         }
00601 }
00602 
00603 
00604 BOOL LLAudioEngine::preloadSound(const LLUUID &uuid)
00605 {
00606         gAudiop->getAudioData(uuid);    // We don't care about the return value, this is just to make sure
00607                                                                         // that we have an entry, which will mean that the audio engine knows about this
00608 
00609         if (gAudioDecodeMgrp->addDecodeRequest(uuid))
00610         {
00611                 // This means that we do have a local copy, and we're working on decoding it.
00612                 return TRUE;
00613         }
00614 
00615         // At some point we need to have the audio/asset system check the static VFS
00616         // before it goes off and fetches stuff from the server.
00617         //llwarns << "Used internal preload for non-local sound" << llendl;
00618         return FALSE;
00619 }
00620 
00621 
00622 BOOL LLAudioEngine::isWindEnabled()
00623 {
00624         return mEnableWind;
00625 }
00626 
00627 
00628 void LLAudioEngine::setMuted(BOOL muted)
00629 {
00630         mMuted = muted;
00631         enableWind(!mMuted);
00632 }
00633 
00634 
00635 void LLAudioEngine::setMasterGain(const F32 gain)
00636 {
00637         mMasterGain = gain;
00638         setInternalGain(gain);
00639 }
00640 
00641 F32 LLAudioEngine::getMasterGain()
00642 {
00643         return mMasterGain;
00644 }
00645 
00646 F32 LLAudioEngine::getInternetStreamGain()
00647 {
00648         return mInternetStreamGain;
00649 }
00650 
00651 void LLAudioEngine::setMaxWindGain(F32 gain)
00652 {
00653         mMaxWindGain = gain;
00654 }
00655 
00656 
00657 F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec)
00658 {
00659         F64 gain = 0.0;
00660         
00661         gain = wind_vec.magVec();
00662 
00663         if (gain)
00664         {
00665                 if (gain > 20)
00666                 {
00667                         gain = 20;
00668                 }
00669                 gain = gain/20.0;
00670         }
00671 
00672         return (gain);
00673 } 
00674 
00675 
00676 F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec)
00677 {
00678         LLVector3 listen_right;
00679         F64 theta;
00680   
00681         // Wind frame is in listener-relative coordinates
00682         LLVector3 norm_wind = wind_vec;
00683         norm_wind.normVec();
00684         listen_right.setVec(1.0,0.0,0.0);
00685 
00686         // measure angle between wind vec and listener right axis (on 0,PI)
00687         theta = acos(norm_wind * listen_right);
00688 
00689         // put it on 0, 1
00690         theta /= F_PI;                                  
00691 
00692         // put it on [0, 0.5, 0]
00693         if (theta > 0.5) theta = 1.0-theta;
00694         if (theta < 0) theta = 0;
00695 
00696         return (theta);
00697 }
00698 
00699 
00700 F64 LLAudioEngine::mapWindVecToPan(LLVector3 wind_vec)
00701 {
00702         LLVector3 listen_right;
00703         F64 theta;
00704   
00705         // Wind frame is in listener-relative coordinates
00706         listen_right.setVec(1.0,0.0,0.0);
00707 
00708         LLVector3 norm_wind = wind_vec;
00709         norm_wind.normVec();
00710 
00711         // measure angle between wind vec and listener right axis (on 0,PI)
00712         theta = acos(norm_wind * listen_right);
00713 
00714         // put it on 0, 1
00715         theta /= F_PI;                                  
00716 
00717         return (theta);
00718 }
00719 
00720 
00721 void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const LLVector3d &pos_global)
00722 {
00723         // Create a new source (since this can't be associated with an existing source.
00724         //llinfos << "Localized: " << audio_uuid << llendl;
00725 
00726         if (mMuted)
00727         {
00728                 return;
00729         }
00730 
00731         LLUUID source_id;
00732         source_id.generate();
00733 
00734         LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain);
00735         gAudiop->addAudioSource(asp);
00736         if (pos_global.isExactlyZero())
00737         {
00738                 asp->setAmbient(TRUE);
00739         }
00740         else
00741         {
00742                 asp->setPositionGlobal(pos_global);
00743         }
00744         asp->updatePriority();
00745         asp->play(audio_uuid);
00746 }
00747 
00748 
00749 void LLAudioEngine::setListenerPos(LLVector3 aVec)
00750 {
00751         mListenerp->setPosition(aVec);  
00752 }
00753 
00754 
00755 LLVector3 LLAudioEngine::getListenerPos()
00756 {
00757         if (mListenerp)
00758         {
00759                 return(mListenerp->getPosition());  
00760         }
00761         else
00762         {
00763                 return(LLVector3::zero);
00764         }
00765 }
00766 
00767 
00768 void LLAudioEngine::setListenerVelocity(LLVector3 aVec)
00769 {
00770         mListenerp->setVelocity(aVec);  
00771 }
00772 
00773 
00774 void LLAudioEngine::translateListener(LLVector3 aVec)
00775 {
00776         mListenerp->translate(aVec);    
00777 }
00778 
00779 
00780 void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at)
00781 {
00782         mListenerp->orient(up, at);  
00783 }
00784 
00785 
00786 void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at)
00787 {
00788         mListenerp->set(pos,vel,up,at);  
00789 }
00790 
00791 
00792 void LLAudioEngine::setDopplerFactor(F32 factor)
00793 {
00794         if (mListenerp)
00795         {
00796                 mListenerp->setDopplerFactor(factor);  
00797         }
00798 }
00799 
00800 
00801 F32 LLAudioEngine::getDopplerFactor()
00802 {
00803         if (mListenerp)
00804         {
00805                 return mListenerp->getDopplerFactor();
00806         }
00807         else
00808         {
00809                 return 0.f;
00810         }
00811 }
00812 
00813 
00814 void LLAudioEngine::setDistanceFactor(F32 factor)
00815 {
00816         if (mListenerp)
00817         {
00818                 mListenerp->setDistanceFactor(factor);  
00819         }
00820 }
00821 
00822 
00823 F32 LLAudioEngine::getDistanceFactor()
00824 {
00825         if (mListenerp)
00826         {
00827                 return mListenerp->getDistanceFactor();
00828         }
00829         else
00830         {
00831                 return 0.f;
00832         }
00833 }
00834 
00835 
00836 void LLAudioEngine::setRolloffFactor(F32 factor)
00837 {
00838         if (mListenerp)
00839         {
00840                 mListenerp->setRolloffFactor(factor);  
00841         }
00842 }
00843 
00844 
00845 F32 LLAudioEngine::getRolloffFactor()
00846 {
00847         if (mListenerp)
00848         {
00849                 return mListenerp->getRolloffFactor();  
00850         }
00851         else
00852         {
00853                 return 0.f;
00854         }
00855 }
00856 
00857 
00858 void LLAudioEngine::commitDeferredChanges()
00859 {
00860         mListenerp->commitDeferredChanges();  
00861 }
00862 
00863 
00864 LLAudioSource *LLAudioEngine::findAudioSource(const LLUUID &source_id)
00865 {
00866         source_map::iterator iter;
00867         iter = mAllSources.find(source_id);
00868 
00869         if (iter == mAllSources.end())
00870         {
00871                 return NULL;
00872         }
00873         else
00874         {
00875                 return iter->second;
00876         }
00877 }
00878 
00879 
00880 LLAudioData *LLAudioEngine::getAudioData(const LLUUID &audio_uuid)
00881 {
00882         data_map::iterator iter;
00883         iter = mAllData.find(audio_uuid);
00884         if (iter == mAllData.end())
00885         {
00886                 // Create the new audio data
00887                 LLAudioData *adp = new LLAudioData(audio_uuid);
00888                 mAllData[audio_uuid] = adp;
00889                 return adp;
00890         }
00891         else
00892         {
00893                 return iter->second;
00894         }
00895 }
00896 
00897 void LLAudioEngine::addAudioSource(LLAudioSource *asp)
00898 {
00899         mAllSources[asp->getID()] = asp;
00900 }
00901 
00902 
00903 void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
00904 {
00905         source_map::iterator iter;
00906         iter = mAllSources.find(asp->getID());
00907         if (iter == mAllSources.end())
00908         {
00909                 llwarns << "Cleaning up unknown audio source!" << llendl;
00910                 return;
00911         }
00912         delete asp;
00913         mAllSources.erase(iter);
00914 }
00915 
00916 
00917 BOOL LLAudioEngine::hasDecodedFile(const LLUUID &uuid)
00918 {
00919         char uuid_str[UUID_STR_LENGTH];                 /*Flawfinder: ignore*/
00920         uuid.toString(uuid_str);
00921 
00922         std::string wav_path;
00923         wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str);
00924         wav_path += ".dsf";
00925 
00926         if (gDirUtilp->fileExists(wav_path))
00927         {
00928                 return TRUE;
00929         }
00930         else
00931         {
00932                 return FALSE;
00933         }
00934 }
00935 
00936 
00937 BOOL LLAudioEngine::hasLocalFile(const LLUUID &uuid)
00938 {
00939         // See if it's in the VFS.
00940         return gVFS->getExists(uuid, LLAssetType::AT_SOUND);
00941 }
00942 
00943 
00944 void LLAudioEngine::startNextTransfer()
00945 {
00946         //llinfos << "LLAudioEngine::startNextTransfer()" << llendl;
00947         if (mCurrentTransfer.notNull() || getMuted())
00948         {
00949                 //llinfos << "Transfer in progress, aborting" << llendl;
00950                 return;
00951         }
00952 
00953         // Get the ID for the next asset that we want to transfer.
00954         // Pick one in the following order:
00955         LLUUID asset_id;
00956         S32 i;
00957         LLAudioSource *asp = NULL;
00958         LLAudioData *adp = NULL;
00959         data_map::iterator data_iter;
00960 
00961         // Check all channels for currently playing sounds.
00962         F32 max_pri = -1.f;
00963         for (i = 0; i < MAX_CHANNELS; i++)
00964         {
00965                 if (!mChannels[i])
00966                 {
00967                         continue;
00968                 }
00969 
00970                 asp = mChannels[i]->getSource();
00971                 if (!asp)
00972                 {
00973                         continue;
00974                 }
00975                 if (asp->getPriority() <= max_pri)
00976                 {
00977                         continue;
00978                 }
00979 
00980                 if (asp->getPriority() <= max_pri)
00981                 {
00982                         continue;
00983                 }
00984 
00985                 adp = asp->getCurrentData();
00986                 if (!adp)
00987                 {
00988                         continue;
00989                 }
00990 
00991                 if (!adp->hasLocalData() && adp->hasValidData())
00992                 {
00993                         asset_id = adp->getID();
00994                         max_pri = asp->getPriority();
00995                 }
00996         }
00997 
00998         // Check all channels for currently queued sounds.
00999         if (asset_id.isNull())
01000         {
01001                 max_pri = -1.f;
01002                 for (i = 0; i < MAX_CHANNELS; i++)
01003                 {
01004                         if (!mChannels[i])
01005                         {
01006                                 continue;
01007                         }
01008 
01009                         LLAudioSource *asp;
01010                         asp = mChannels[i]->getSource();
01011                         if (!asp)
01012                         {
01013                                 continue;
01014                         }
01015 
01016                         if (asp->getPriority() <= max_pri)
01017                         {
01018                                 continue;
01019                         }
01020 
01021                         adp = asp->getQueuedData();
01022                         if (!adp)
01023                         {
01024                                 continue;
01025                         }
01026 
01027                         if (!adp->hasLocalData() && adp->hasValidData())
01028                         {
01029                                 asset_id = adp->getID();
01030                                 max_pri = asp->getPriority();
01031                         }
01032                 }
01033         }
01034 
01035         // Check all live channels for other sounds (preloads).
01036         if (asset_id.isNull())
01037         {
01038                 max_pri = -1.f;
01039                 for (i = 0; i < MAX_CHANNELS; i++)
01040                 {
01041                         if (!mChannels[i])
01042                         {
01043                                 continue;
01044                         }
01045 
01046                         LLAudioSource *asp;
01047                         asp = mChannels[i]->getSource();
01048                         if (!asp)
01049                         {
01050                                 continue;
01051                         }
01052 
01053                         if (asp->getPriority() <= max_pri)
01054                         {
01055                                 continue;
01056                         }
01057 
01058 
01059                         for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++)
01060                         {
01061                                 LLAudioData *adp = data_iter->second;
01062                                 if (!adp)
01063                                 {
01064                                         continue;
01065                                 }
01066 
01067                                 if (!adp->hasLocalData() && adp->hasValidData())
01068                                 {
01069                                         asset_id = adp->getID();
01070                                         max_pri = asp->getPriority();
01071                                 }
01072                         }
01073                 }
01074         }
01075 
01076         // Check all sources
01077         if (asset_id.isNull())
01078         {
01079                 max_pri = -1.f;
01080                 source_map::iterator source_iter;
01081                 for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++)
01082                 {
01083                         asp = source_iter->second;
01084                         if (!asp)
01085                         {
01086                                 continue;
01087                         }
01088 
01089                         if (asp->getPriority() <= max_pri)
01090                         {
01091                                 continue;
01092                         }
01093 
01094                         adp = asp->getCurrentData();
01095                         if (adp && !adp->hasLocalData() && adp->hasValidData())
01096                         {
01097                                 asset_id = adp->getID();
01098                                 max_pri = asp->getPriority();
01099                                 continue;
01100                         }
01101 
01102                         adp = asp->getQueuedData();
01103                         if (adp && !adp->hasLocalData() && adp->hasValidData())
01104                         {
01105                                 asset_id = adp->getID();
01106                                 max_pri = asp->getPriority();
01107                                 continue;
01108                         }
01109 
01110                         for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++)
01111                         {
01112                                 LLAudioData *adp = data_iter->second;
01113                                 if (!adp)
01114                                 {
01115                                         continue;
01116                                 }
01117 
01118                                 if (!adp->hasLocalData() && adp->hasValidData())
01119                                 {
01120                                         asset_id = adp->getID();
01121                                         max_pri = asp->getPriority();
01122                                         break;
01123                                 }
01124                         }
01125                 }
01126         }
01127 
01128         if (asset_id.notNull())
01129         {
01130                 llinfos << "Getting asset data for: " << asset_id << llendl;
01131                 gAudiop->mCurrentTransfer = asset_id;
01132                 gAudiop->mCurrentTransferTimer.reset();
01133                 gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND,
01134                                                                         assetCallback, NULL);
01135         }
01136         else
01137         {
01138                 //llinfos << "No pending transfers?" << llendl;
01139         }
01140 }
01141 
01142 
01143 // static
01144 void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status)
01145 {
01146         if (result_code)
01147         {
01148                 llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl;
01149                 // Need to mark data as bad to avoid constant rerequests.
01150                 LLAudioData *adp = gAudiop->getAudioData(uuid);
01151                 if (adp)
01152         {
01153                         adp->setHasValidData(FALSE);
01154                         adp->setHasLocalData(FALSE);
01155                         adp->setHasDecodedData(FALSE);
01156                 }
01157         }
01158         else
01159         {
01160                 LLAudioData *adp = gAudiop->getAudioData(uuid);
01161                 if (!adp)
01162         {
01163                         // Should never happen
01164                         llwarns << "Got asset callback without audio data for " << uuid << llendl;
01165         }
01166                 else
01167                 {
01168                         adp->setHasValidData(TRUE);
01169                     adp->setHasLocalData(TRUE);
01170                     gAudioDecodeMgrp->addDecodeRequest(uuid);
01171                 }
01172         }
01173         gAudiop->mCurrentTransfer = LLUUID::null;
01174         gAudiop->startNextTransfer();
01175 }
01176 
01177 
01178 //
01179 // LLAudioSource implementation
01180 //
01181 
01182 
01183 LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 gain)
01184 :       mID(id),
01185         mOwnerID(owner_id),
01186         mPriority(0.f),
01187         mGain(gain),
01188         mAmbient(FALSE),
01189         mLoop(FALSE),
01190         mSyncMaster(FALSE),
01191         mSyncSlave(FALSE),
01192         mQueueSounds(FALSE),
01193         mPlayedOnce(FALSE),
01194         mChannelp(NULL),
01195         mCurrentDatap(NULL),
01196         mQueuedDatap(NULL)
01197 {
01198 }
01199 
01200 
01201 LLAudioSource::~LLAudioSource()
01202 {
01203         if (mChannelp)
01204         {
01205                 // Stop playback of this sound
01206                 mChannelp->setSource(NULL);
01207                 mChannelp = NULL;
01208         }
01209 }
01210 
01211 
01212 void LLAudioSource::setChannel(LLAudioChannel *channelp)
01213 {
01214         if (channelp == mChannelp)
01215         {
01216                 return;
01217         }
01218 
01219         mChannelp = channelp;
01220 }
01221 
01222 
01223 void LLAudioSource::update()
01224 {
01225         if (!getCurrentBuffer())
01226         {
01227                 if (getCurrentData())
01228                 {
01229                         // Hack - try and load the sound.  Will do this as a callback
01230                         // on decode later.
01231                         if (getCurrentData()->load())
01232                         {
01233                                 play(getCurrentData()->getID());
01234                         }                       
01235                 }
01236         }
01237 }
01238 
01239 void LLAudioSource::updatePriority()
01240 {
01241         if (isAmbient())
01242         {
01243                 mPriority = 1.f;
01244         }
01245         else
01246         {
01247                 // Priority is based on distance
01248                 LLVector3 dist_vec;
01249                 dist_vec.setVec(getPositionGlobal());
01250                 dist_vec -= gAudiop->getListenerPos();
01251                 F32 dist_squared = llmax(1.f, dist_vec.magVecSquared());
01252 
01253                 mPriority = mGain / dist_squared;
01254         }
01255 }
01256 
01257 BOOL LLAudioSource::setupChannel()
01258 {
01259         LLAudioData *adp = getCurrentData();
01260 
01261         if (!adp->getBuffer())
01262         {
01263                 // We're not ready to play back the sound yet, so don't try and allocate a channel for it.
01264                 //llwarns << "Aborting, no buffer" << llendl;
01265                 return FALSE;
01266         }
01267 
01268 
01269         if (!mChannelp)
01270         {
01271                 // Update the priority, in case we need to push out another channel.
01272                 updatePriority();
01273 
01274                 setChannel(gAudiop->getFreeChannel(getPriority()));
01275         }
01276 
01277         if (!mChannelp)
01278         {
01279                 // Ugh, we don't have any free channels.
01280                 // Now we have to reprioritize.
01281                 // For now, just don't play the sound.
01282                 //llwarns << "Aborting, no free channels" << llendl;
01283                 return FALSE;
01284         }
01285 
01286         mChannelp->setSource(this);
01287         return TRUE;
01288 }
01289 
01290 
01291 BOOL LLAudioSource::play(const LLUUID &audio_uuid)
01292 {
01293         if (audio_uuid.isNull())
01294         {
01295                 if (getChannel())
01296                 {
01297                         getChannel()->setSource(NULL);
01298                         setChannel(NULL);
01299                         addAudioData(NULL, TRUE);
01300                 }
01301         }
01302         // Reset our age timeout if someone attempts to play the source.
01303         mAgeTimer.reset();
01304 
01305         LLAudioData *adp = gAudiop->getAudioData(audio_uuid);
01306 
01307         BOOL has_buffer = gAudiop->updateBufferForData(adp, audio_uuid);
01308 
01309 
01310         addAudioData(adp);
01311 
01312         if (!has_buffer)
01313         {
01314                 // Don't bother trying to set up a channel or anything, we don't have an audio buffer.
01315                 return FALSE;
01316         }
01317 
01318         if (!setupChannel())
01319         {
01320                 return FALSE;
01321         }
01322 
01323         if (isSyncSlave())
01324         {
01325                 // A sync slave, it doesn't start playing until it's synced up with the master.
01326                 // Flag this channel as waiting for sync, and return true.
01327                 getChannel()->setWaiting(TRUE);
01328                 return TRUE;
01329         }
01330 
01331         getChannel()->play();
01332         return TRUE;
01333 }
01334 
01335 
01336 BOOL LLAudioSource::isDone()
01337 {
01338         const F32 MAX_AGE = 60.f;
01339         const F32 MAX_UNPLAYED_AGE = 15.f;
01340         if (isLoop())
01341         {
01342                 // Looped sources never die on their own.
01343                 return FALSE;
01344         }
01345 
01346 
01347         if (hasPendingPreloads())
01348         {
01349                 return FALSE;
01350         }
01351 
01352         if (mQueuedDatap)
01353         {
01354                 // Don't kill this sound if we've got something queued up to play.
01355                 return FALSE;
01356         }
01357 
01358         F32 elapsed = mAgeTimer.getElapsedTimeF32();
01359 
01360         // This is a single-play source
01361         if (!mChannelp)
01362         {
01363                 if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce)
01364                 {
01365                         // We don't have a channel assigned, and it's been
01366                         // over 5 seconds since we tried to play it.  Don't bother.
01367                         //llinfos << "No channel assigned, source is done" << llendl;
01368                         return TRUE;
01369                 }
01370                 else
01371                 {
01372                         return FALSE;
01373                 }
01374         }
01375 
01376         if (mChannelp->isPlaying())
01377         {
01378                 if (elapsed > MAX_AGE)
01379                 {
01380                         // Arbitarily cut off non-looped sounds when they're 20 seconds old.
01381                         return TRUE;
01382                 }
01383                 else
01384                 {
01385                         // Sound is still playing and we haven't timed out, don't kill it.
01386                         return FALSE;
01387                 }
01388         }
01389 
01390         if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce)
01391         {
01392                 // The sound isn't playing back after 5 seconds or we're already done playing it, kill it.
01393                 return TRUE;
01394         }
01395 
01396         return FALSE;
01397 }
01398 
01399 
01400 void LLAudioSource::addAudioData(LLAudioData *adp, const BOOL set_current)
01401 {
01402         // Only handle a single piece of audio data associated with a source right now,
01403         // until I implement prefetch.
01404         if (set_current)
01405         {
01406                 if (!mCurrentDatap)
01407                 {
01408                         mCurrentDatap = adp;
01409                         if (mChannelp)
01410                         {
01411                                 mChannelp->updateBuffer();
01412                                 mChannelp->play();
01413                         }
01414 
01415                         // Make sure the audio engine knows that we want to request this sound.
01416                         gAudiop->startNextTransfer();
01417                         return;
01418                 }
01419                 else if (mQueueSounds)
01420                 {
01421                         // If we have current data, and we're queuing, put
01422                         // the object onto the queue.
01423                         if (mQueuedDatap)
01424                         {
01425                                 // We only queue one sound at a time, and it's a FIFO.
01426                                 // Don't put it onto the queue.
01427                                 return;
01428                         }
01429 
01430                         if (adp == mCurrentDatap && isLoop())
01431                         {
01432                                 // No point in queueing the same sound if
01433                                 // we're looping.
01434                                 return;
01435                         }
01436                         mQueuedDatap = adp;
01437 
01438                         // Make sure the audio engine knows that we want to request this sound.
01439                         gAudiop->startNextTransfer();
01440                 }
01441                 else
01442                 {
01443                         if (mCurrentDatap != adp)
01444                         {
01445                                 // Right now, if we're currently playing this sound in a channel, we
01446                                 // update the buffer that the channel's associated with
01447                                 // and play it.  This may not be the correct behavior.
01448                                 mCurrentDatap = adp;
01449                                 if (mChannelp)
01450                                 {
01451                                         mChannelp->updateBuffer();
01452                                         mChannelp->play();
01453                                 }
01454                                 // Make sure the audio engine knows that we want to request this sound.
01455                                 gAudiop->startNextTransfer();
01456                         }
01457                 }
01458         }
01459         else
01460         {
01461                 // Add it to the preload list.
01462                 mPreloadMap[adp->getID()] = adp;
01463                 gAudiop->startNextTransfer();
01464         }
01465 }
01466 
01467 
01468 BOOL LLAudioSource::hasPendingPreloads() const
01469 {
01470         // Check to see if we've got any preloads on deck for this source
01471         data_map::const_iterator iter;
01472         for (iter = mPreloadMap.begin(); iter != mPreloadMap.end(); iter++)
01473         {
01474                 LLAudioData *adp = iter->second;
01475                 if (!adp->hasDecodedData())
01476                 {
01477                         // This source is still waiting for a preload
01478                         return TRUE;
01479                 }
01480         }
01481 
01482         return FALSE;
01483 }
01484 
01485 
01486 LLAudioData *LLAudioSource::getCurrentData()
01487 {
01488         return mCurrentDatap;
01489 }
01490 
01491 LLAudioData *LLAudioSource::getQueuedData()
01492 {
01493         return mQueuedDatap;
01494 }
01495 
01496 LLAudioBuffer *LLAudioSource::getCurrentBuffer()
01497 {
01498         if (!mCurrentDatap)
01499         {
01500                 return NULL;
01501         }
01502 
01503         return mCurrentDatap->getBuffer();
01504 }
01505 
01506 
01507 
01508 
01509 //
01510 // LLAudioChannel implementation
01511 //
01512 
01513 
01514 LLAudioChannel::LLAudioChannel() :
01515         mCurrentSourcep(NULL),
01516         mCurrentBufferp(NULL),
01517         mLoopedThisFrame(FALSE),
01518         mWaiting(FALSE)
01519 {
01520 }
01521 
01522 
01523 LLAudioChannel::~LLAudioChannel()
01524 {
01525         // Need to disconnect any sources which are using this channel.
01526         //llinfos << "Cleaning up audio channel" << llendl;
01527         if (mCurrentSourcep)
01528         {
01529                 mCurrentSourcep->setChannel(NULL);
01530         }
01531         mCurrentBufferp = NULL;
01532 }
01533 
01534 
01535 void LLAudioChannel::setSource(LLAudioSource *sourcep)
01536 {
01537         //llinfos << this << ": setSource(" << sourcep << ")" << llendl;
01538 
01539         if (!sourcep)
01540         {
01541                 // Clearing the source for this channel, don't need to do anything.
01542                 //llinfos << "Clearing source for channel" << llendl;
01543                 cleanup();
01544                 mCurrentSourcep = NULL;
01545                 mWaiting = FALSE;
01546                 return;
01547         }
01548 
01549         if (sourcep == mCurrentSourcep)
01550         {
01551                 // Don't reallocate the channel, this will make FMOD goofy.
01552                 //llinfos << "Calling setSource with same source!" << llendl;
01553         }
01554 
01555         mCurrentSourcep = sourcep;
01556         updateBuffer();
01557         update3DPosition();
01558 }
01559 
01560 
01561 BOOL LLAudioChannel::updateBuffer()
01562 {
01563         if (!mCurrentSourcep)
01564         {
01565                 // This channel isn't associated with any source, nothing
01566                 // to be updated
01567                 return FALSE;
01568         }
01569 
01570         LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer();
01571         if (bufferp == mCurrentBufferp)
01572         {
01573                 if (bufferp)
01574                 {
01575                         // The source hasn't changed what buffer it's playing
01576                         bufferp->mLastUseTimer.reset();
01577                         bufferp->mInUse = TRUE;
01578                 }
01579                 return FALSE;
01580         }
01581 
01582         //
01583         // The source changed what buffer it's playing.  Whe need to clean up the
01584         // existing fmod channel
01585         //
01586         cleanup();
01587 
01588         mCurrentBufferp = bufferp;
01589         if (bufferp)
01590         {
01591                 bufferp->mLastUseTimer.reset();
01592                 bufferp->mInUse = TRUE;
01593         }
01594 
01595         if (!mCurrentBufferp)
01596         {
01597                 // There's no new buffer to be played, so we just abort.
01598                 return FALSE;
01599         }
01600 
01601         return TRUE;
01602 }
01603 
01604 
01605 
01606 
01607 //
01608 // LLAudioData implementation
01609 //
01610 
01611 
01612 LLAudioData::LLAudioData(const LLUUID &uuid) :
01613         mID(uuid),
01614         mBufferp(NULL),
01615         mHasLocalData(FALSE),
01616         mHasDecodedData(FALSE),
01617         mHasValidData(TRUE)
01618 {
01619         if (uuid.isNull())
01620         {
01621                 // This is a null sound.
01622                 return;
01623         }
01624 
01625         if (gAudiop->hasDecodedFile(uuid))
01626         {
01627                 // Already have a decoded version, don't need to decode it.
01628                 mHasLocalData = TRUE;
01629                 mHasDecodedData = TRUE;
01630         }
01631         else if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND))
01632         {
01633                 mHasLocalData = TRUE;
01634         }
01635 }
01636 
01637 
01638 BOOL LLAudioData::load()
01639 {
01640         // For now, just assume we're going to use one buffer per audiodata.
01641         if (mBufferp)
01642         {
01643                 // We already have this sound in a buffer, don't do anything.
01644                 llinfos << "Already have a buffer for this sound, don't bother loading!" << llendl;
01645                 return TRUE;
01646         }
01647         
01648         mBufferp = gAudiop->getFreeBuffer();
01649         if (!mBufferp)
01650         {
01651                 // No free buffers, abort.
01652                 llinfos << "Not able to allocate a new audio buffer, aborting." << llendl;
01653                 return FALSE;
01654         }
01655 
01656         char uuid_str[UUID_STR_LENGTH];                 /*Flawfinder: ignore*/
01657         char wav_path[MAX_PATH];                                /*Flawfinder: ignore*/
01658         mID.toString(uuid_str);
01659         snprintf(wav_path, MAX_PATH, "%s.dsf",gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str());  /* Flawfinder: ignore */
01660 
01661         if (!mBufferp->loadWAV(wav_path))
01662         {
01663                 // Hrm.  Right now, let's unset the buffer, since it's empty.
01664                 gAudiop->cleanupBuffer(mBufferp);
01665                 mBufferp = NULL;
01666 
01667                 return FALSE;
01668         }
01669         mBufferp->mAudioDatap = this;
01670         return TRUE;
01671 }
01672 
01673 

Generated on Fri May 16 08:31:54 2008 for SecondLife by  doxygen 1.5.5