bool LLAudioSource::setupChannel() { LLAudioData *adp = getCurrentData(); if (!adp->getBuffer()) { // We're not ready to play back the sound yet, so don't try and allocate a channel for it. //llwarns << "Aborting, no buffer" << llendl; return false; } if (!mChannelp) { // Update the priority, in case we need to push out another channel. updatePriority(); setChannel(gAudiop->getFreeChannel(getPriority())); } if (!mChannelp) { // Ugh, we don't have any free channels. // Now we have to reprioritize. // For now, just don't play the sound. //llwarns << "Aborting, no free channels" << llendl; return false; } mChannelp->setSource(this); return true; }
void LLAudioSource::update() { if(mCorrupted) { return ; //no need to update } if (!getCurrentBuffer()) { LLAudioData *adp = getCurrentData(); if (adp) { // Hack - try and load the sound. Will do this as a callback // on decode later. if (adp->load() && adp->getBuffer()) { play(adp->getID()); } else if (adp->hasCompletedDecode()) // Only mark corrupted after decode is done { llwarns << "Marking LLAudioSource corrupted for " << adp->getID() << llendl; mCorrupted = true ; } } } }
// <FS:Ansariel> Asset blacklisting void LLAudioEngine::removeAudioData(const LLUUID& audio_uuid) { if (audio_uuid.isNull()) { return; } data_map::iterator iter = mAllData.find(audio_uuid); if (iter != mAllData.end()) { uuid_vec_t delete_list; source_map::iterator iter2; for (iter2 = mAllSources.begin(); iter2 != mAllSources.end(); ++iter2) { LLAudioSource* sourcep = iter2->second; if (sourcep && sourcep->getCurrentData() && sourcep->getCurrentData()->getID() == audio_uuid) { delete_list.push_back(iter2->first); } } uuid_vec_t::iterator delete_list_end = delete_list.end(); for (uuid_vec_t::iterator del_it = delete_list.begin(); del_it != delete_list_end; ++del_it) { LLUUID source_id = *del_it; LLAudioSource* sourcep = mAllSources[source_id]; LLAudioChannel* chan = sourcep->getChannel(); delete sourcep; mAllSources.erase(source_id); if (chan) { chan->cleanup(); } } LLAudioData* data = iter->second; if (data) { LLAudioBuffer* buf = data->getBuffer(); if (buf) { S32 i; for (i = 0; i < MAX_BUFFERS; ++i) { if (mBuffers[i] == buf) { mBuffers[i] = NULL; } } delete buf; } delete data; } mAllData.erase(audio_uuid); } }
void LLAudioSource::update() { if(mCorrupted) { return ; //no need to update } // If data is queued up and we aren't playing it, shuffle it to current and try to load it. if(isQueueSounds() && mPlayedOnce && mQueuedDatap && !mChannelp) { mCurrentDatap = mQueuedDatap; mQueuedDatap = NULL; //Make sure this source looks like its brand new again to prevent removal. mPlayedOnce = false; mAgeTimer.reset(); } LLAudioData *adp = getCurrentData(); if (adp && !adp->getBuffer()) { if(adp->getLoadState() == LLAudioData::STATE_LOAD_ERROR) { LL_WARNS("AudioEngine") << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL; mCorrupted = true ; } else if(adp->getLoadState() == LLAudioData::STATE_LOAD_READY) { // Update the audio buffer first - load a sound if we have it. // Note that this could potentially cause us to waste time updating buffers // for sounds that actually aren't playing, although this should be mitigated // by the fact that we limit the number of buffers, and we flush buffers based // on priority. adp->load(); //If it fails, just try again next update. } else { //The sound wasn't preloaded yet... so we must kick off the process. adp->updateLoadState(); } } }
void LLAudioEngine::idle(F32 max_decode_time) { if (max_decode_time <= 0.f) { max_decode_time = default_max_decode_time; } // "Update" all of our audio sources, clean up dead ones. // Primarily does position updating, cleanup of unused audio sources. // Also does regeneration of the current priority of each audio source. S32 i; for (i = 0; i < MAX_BUFFERS; i++) { if (mBuffers[i]) { mBuffers[i]->mInUse = false; } } //Iterate down all queued sources. Remove finished ones, sort active ones by priority. Find highest priority 'master' source if present. LLAudioSource *sync_masterp = NULL; //Highest priority syncmaster LLAudioSource *sync_slavep = NULL; //Highest priority syncslave //Priority queue that will be filled with soundsources that have a high likeleyhood of being able to start [re]playing this idle tick. //Sort order: Primary: priority. Secondary: syncmaster. Tertiary: syncslave std::priority_queue<LLAudioSource*,std::vector<LLAudioSource*,boost::pool_allocator<LLAudioSource*> >,SourcePriorityComparator> queue; //Have to put syncslaves into a temporary list until the syncmaster state is determined. //If the syncmaster might be started, or just looped, insert all pending/looping syncslaves into the priority queue. //If the there is no active syncmaster, then stop any currently looping syncslaves and add none to the priority queue. //This is necessary as any looping soundsources to be stopped, MUST be stopped before iterating down the priority queue. static std::vector<LLAudioSource*> slave_list; slave_list.clear(); //Iterate over all sources. Update their decode or 'done' state, as well as their priorities. //Also add sources that might be able to start playing to the priority queue. //Only sources without channels should be added to priority queue. //Syncslaves must put into the slave list instead of the priority queue. for (source_map::iterator iter = mAllSources.begin(); iter != mAllSources.end();) { LLAudioSource *sourcep = iter->second; //Load/decode/queue pop sourcep->update(); //Done after update, as failure to load might mark source as corrupt, which causes isDone to return true. if (sourcep->isDone()) { // The source is done playing, clean it up. delete sourcep; mAllSources.erase(iter++); continue; } // Increment iter here (it is not used anymore), so we can use continue below to move on to the next source. ++iter; if(!sourcep->isLoop() && sourcep->mPlayedOnce && (!sourcep->mChannelp || !sourcep->mChannelp->isPlaying())) { continue; } LLAudioData *adp = sourcep->getCurrentData(); //If there is no current data at all, or if it hasn't loaded, we must skip this source. if (!adp || !adp->getBuffer()) { continue; } sourcep->updatePriority(); //Calculates current priority. 1.f=ambient. 0.f=muted. Otherwise based off of distance. if (sourcep->getPriority() < F_APPROXIMATELY_ZERO) { // Muted, or nothing queued, or too far, so we don't care. continue; } else if(sourcep->isSyncMaster()) { if(!sync_masterp || sourcep->getPriority() > sync_masterp->getPriority()) { if(sync_masterp && !sync_masterp->getChannel()) queue.push(sync_masterp); //Add lower-priority soundmaster to the queue as a normal sound. sync_masterp = sourcep; //Don't add master to the queue yet. //Add it after highest-priority sound slave is found so we can outrank its priority. continue; } //Else fall through like a normal sound. } else if(sourcep->isSyncSlave()) { if(!sync_slavep || sourcep->getPriority() > sync_slavep->getPriority()) { sync_slavep = sourcep; } //Don't add to the priority queue quite yet. Best primary syncmaster candidate may not have been determined yet. slave_list.push_back(sourcep); continue; } if(sourcep->getChannel()) { //If this is just a regular sound and is currently playing then do nothing special. continue; } //Add to our queue. Highest priority will be at the front. queue.push(sourcep); } // Do this BEFORE we update the channels // Update the channels to sync up with any changes that the source made, // such as changing what sound was playing. updateChannels(); //Loop over all syncsaves. If no syncmaster, stop looping ones, else add ones that need [re]started to the priority queue. //Normally there are zero to one syncslaves, so this loop isn't typically expensive. for(std::vector<LLAudioSource*>::iterator iter=slave_list.begin();iter!=slave_list.end();++iter) { if(!sync_masterp) { //Stop any looping syncslaves. I'm not sure this behavior is correct, but letting looping syncslaves run //off on their own seems wrong. The lsl documentation is unclear. if((*iter)->getChannel() && (*iter)->isLoop()) { (*iter)->getChannel()->cleanup(); } } //If the syncmaster already has a channel and hasn't looped, then we can skip syncslaves this idle tick (there's nothing to do). else if((!sync_masterp->getChannel() || sync_masterp->getChannel()->mLoopedThisFrame)) { //Add syncslaves that we might want to [re]start. if(!(*iter)->getChannel() || (*iter)->isLoop()) queue.push((*iter)); } } if(sync_masterp) { //Syncmaster must have priority greater than or equal to priority of highest priority syncslave. //The case of slave priority equaling master priority is handled in the comparator (SourcePriorityComparator). if(sync_slavep) sync_masterp->setPriority(sync_slavep->getPriority()); if(!sync_masterp->getChannel()) { queue.push(sync_masterp); } } // Dispatch all soundsources. bool syncmaster_started = sync_masterp && sync_masterp->getChannel() && sync_masterp->getChannel()->mLoopedThisFrame; while(!queue.empty()) { LLAudioSource *sourcep = queue.top(); queue.pop(); //If the syncmaster hasn't just started playing, or hasn't just looped then skip this soundslave, //as there's nothing to do with it yet. if (sourcep->isSyncSlave() && !syncmaster_started) { continue; } LLAudioChannel *channelp = sourcep->getChannel(); if (!channelp) { //No more channels. We can break here, as in theory, any lower priority sounds should have had their //channel already stolen. There should be nothing playing, nor playable, when iterating beyond this point. if(!(channelp = getFreeChannel(sourcep->getPriority()))) { break; } //If this is the primary syncmaster that we just started, then [re]start syncslaves further down in the priority queue. //Due to sorting and priority fudgery, the syncmaster is ALWAYS before any syncslaves in this loop. syncmaster_started |= (sourcep == sync_masterp); //setSource calls updateBuffer and update3DPosition, and resets the source mAgeTimer channelp->setSource(sourcep); } if(sourcep->isSyncSlave()) channelp->playSynced(sync_masterp->getChannel()); else channelp->play(); } // Sync up everything that the audio engine needs done. commitDeferredChanges(); // Flush unused buffers that are stale enough for (i = 0; i < MAX_BUFFERS; i++) { if (mBuffers[i]) { if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) { LL_DEBUGS("AudioEngine") << "Flushing unused buffer!" << LL_ENDL; mBuffers[i]->mAudioDatap->mBufferp = NULL; delete mBuffers[i]; mBuffers[i] = NULL; } } } // Clear all of the looped flags for the channels for (i = 0; i < MAX_CHANNELS; i++) { if (mChannels[i]) { mChannels[i]->mLoopedThisFrame = false; } } // Decode audio files gAudioDecodeMgrp->processQueue(max_decode_time); // Just call here every frame. It makes little sense to call elsewhere, // as it's throttled to one active preloading loading sound at a time anyhow startNextTransfer(); updateInternetStream(); }