void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, // <edit> //const S32 type, const LLVector3d &pos_global) const S32 type, const LLVector3d &pos_global, const LLUUID source_object) // </edit> { // Create a new source (since this can't be associated with an existing source. //llinfos << "Localized: " << audio_uuid << llendl; if (mMuted) { return; } LLUUID source_id; source_id.generate(); // <edit> //LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type); LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type, source_object, true); // </edit> gAudiop->addAudioSource(asp); if (pos_global.isExactlyZero()) { asp->setAmbient(true); } else { asp->setPositionGlobal(pos_global); } asp->updatePriority(); asp->play(audio_uuid); }
void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const S32 type, const LLVector3d &pos_global) { // Create a new source (since this can't be associated with an existing source. //llinfos << "Localized: " << audio_uuid << llendl; if (mMuted || gain == 0.0) { return; } //fix collision sounds under OpenAL F32 fixedGain=llclamp(gain,0.0f,1.0f); if (fixedGain == 0.f) return; LLUUID source_id; source_id.generate(); LLAudioSource *asp = new LLAudioSource(source_id, owner_id, fixedGain, type); gAudiop->addAudioSource(asp); if (pos_global.isExactlyZero()) { asp->setAmbient(true); } else { asp->setPositionGlobal(pos_global); } asp->updatePriority(); asp->play(audio_uuid); }
void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const S32 type, const LLVector3d &pos_global) { // Create a new source (since this can't be associated with an existing source. //llinfos << "Localized: " << audio_uuid << llendl; //If we cannot hear it, dont even try to load the sound. if (mMuted || gain == 0.0) { return; } LLUUID source_id; source_id.generate(); LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type); gAudiop->addAudioSource(asp); if (pos_global.isExactlyZero()) { asp->setAmbient(true); } else { asp->setPositionGlobal(pos_global); } asp->updatePriority(); asp->play(audio_uuid); }
void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const S32 type, const LLVector3d &pos_global, const LLUUID& source_object) { // Create a new source (since this can't be associated with an existing source. //LL_INFOS() << "Localized: " << audio_uuid << LL_ENDL; // NaCl - Do not load silent sounds. if (mMuted || gain <FLT_EPSILON*2) { return; } LLUUID source_id; source_id.generate(); LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type, source_object, true); addAudioSource(asp); if (pos_global.isExactlyZero()) { asp->setAmbient(true); } else { asp->setPositionGlobal(pos_global); } asp->updatePriority(); asp->play(audio_uuid); }
// <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); } }
LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid) : LLPreview( name, rect, title, item_uuid, object_uuid) { LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_sound.xml"); childSetAction("Sound play btn",&LLPreviewSound::playSound,this); childSetAction("Sound audition btn",&LLPreviewSound::auditionSound,this); // <edit> childSetAction("Sound copy uuid btn", &LLPreviewSound::copyUUID, this); childSetAction("Play ambient btn", &LLPreviewSound::playAmbient, this); // </edit> LLButton* button = getChild<LLButton>("Sound play btn"); button->setSoundFlags(LLView::SILENT); button = getChild<LLButton>("Sound audition btn"); button->setSoundFlags(LLView::SILENT); const LLInventoryItem* item = getItem(); mIsCopyable = false; if(item) { const LLPermissions& perm = item->getPermissions(); mIsCopyable = (perm.getCreator() == gAgent.getID()); } childSetCommitCallback("desc", LLPreview::onText, this); childSetText("desc", item->getDescription()); childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); // preload the sound if(item && gAudiop) { gAudiop->preloadSound(item->getAssetUUID()); // <edit> // that thing above doesn't actually start a sound transfer, so I will do it //LLAudioSource *asp = new LLAudioSource(gAgent.getID(), gAgent.getID(), F32(1.0f), LLAudioEngine::AUDIO_TYPE_UI); LLAudioSource *asp = gAgentAvatarp->getAudioSource(gAgent.getID()); LLAudioData *datap = gAudiop->getAudioData(item->getAssetUUID()); asp->addAudioData(datap, FALSE); // </edit> } setTitle(title); if (!getHost()) { LLRect curRect = getRect(); translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); } }
LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) { S32 i; for (i = 0; i < mNumChannels; i++) { if (!mChannels[i]) { // No channel allocated here, use it. mChannels[i] = createChannel(); return mChannels[i]; } else { // Channel is allocated but not playing right now, use it. if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) { LL_DEBUGS("AudioEngine") << "Replacing unused channel" << llendl; mChannels[i]->cleanup(); if (mChannels[i]->getSource()) { mChannels[i]->getSource()->setChannel(NULL); } return mChannels[i]; } } } // All channels used, check priorities. // Find channel with lowest priority and see if we want to replace it. F32 min_priority = 10000.f; LLAudioChannel *min_channelp = NULL; for (i = 0; i < mNumChannels; i++) { LLAudioChannel *channelp = mChannels[i]; LLAudioSource *sourcep = channelp->getSource(); if (sourcep->getPriority() < min_priority) { min_channelp = channelp; min_priority = sourcep->getPriority(); } } if (min_priority > priority || !min_channelp) { // All playing channels have higher priority, return. return NULL; } LL_DEBUGS("AudioEngine") << "Flushing min channel" << llendl; // Flush the minimum priority channel, and return it. min_channelp->cleanup(); return min_channelp; }
void LLAudioEngine::removeAudioData(LLUUID &audio_uuid) { data_map::iterator iter; iter = mAllData.find(audio_uuid); if(iter != mAllData.end()) { source_map::iterator iter2; for (iter2 = mAllSources.begin(); iter2 != mAllSources.end();) { LLAudioSource *sourcep = iter2->second; if(sourcep) { if(sourcep->getCurrentData()) { if(!(sourcep->getCurrentData()->getID().isNull())) { if(sourcep->getCurrentData()->getID().asString() == audio_uuid.asString()) { LLAudioChannel* chan=sourcep->getChannel(); delete sourcep; mAllSources.erase(iter2++); if(chan) chan->cleanup(); } else iter2++; } else iter2++; } else iter2++; } else iter2++; } LLAudioBuffer* buf=((LLAudioData*)iter->second)->getBuffer(); if(buf) { S32 i; for (i = 0; i < MAX_BUFFERS; i++) { if(mBuffers[i] == buf) mBuffers[i] = NULL; } delete buf; } delete iter->second; mAllData[audio_uuid] = NULL; } }
void LLAudioEngine::removeAudioData(LLUUID &audio_uuid) { if(audio_uuid.isNull()) return; data_map::iterator iter = mAllData.find(audio_uuid); if(iter != mAllData.end()) { for (source_map::iterator iter2 = mAllSources.begin(); iter2 != mAllSources.end();) { LLAudioSource *sourcep = iter2->second; if( sourcep && sourcep->getCurrentData() && sourcep->getCurrentData()->getID() == audio_uuid ) { LLAudioChannel* chan=sourcep->getChannel(); if(chan) { LL_DEBUGS("AudioEngine") << "removeAudioData" << LL_ENDL; chan->cleanup(); } delete sourcep; mAllSources.erase(iter2++); } else ++iter2; } if(iter->second) //Shouldn't be null, but playing it safe. { LLAudioBuffer* buf=((LLAudioData*)iter->second)->getBuffer(); if(buf) { for (S32 i = 0; i < MAX_BUFFERS; i++) { if(mBuffers[i] == buf) mBuffers[i] = NULL; } delete buf; } delete iter->second; } mAllData.erase(iter); } }
void LLAudioEngine::updateChannels() { S32 i; for (i = 0; i < MAX_CHANNELS; i++) { if (mChannels[i]) { // set secondary gain if type is available LLAudioSource* source = mChannels[i]->getSource(); if (source) { mChannels[i]->setSecondaryGain(mSecondaryGain[source->getType()]); } mChannels[i]->updateBuffer(); mChannels[i]->update3DPosition(); mChannels[i]->updateLoop(); } } }
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; } } F32 max_priority = -1.f; LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel source_map::iterator iter; for (iter = mAllSources.begin(); iter != mAllSources.end();) { LLAudioSource *sourcep = iter->second; // Update this source sourcep->update(); sourcep->updatePriority(); if (sourcep->isDone()) { // The source is done playing, clean it up. delete sourcep; mAllSources.erase(iter++); continue; } if (sourcep->isMuted()) { ++iter; continue; } if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) { // We could potentially play this sound if its priority is high enough. if (sourcep->getPriority() > max_priority) { max_priority = sourcep->getPriority(); max_sourcep = sourcep; } } // Move on to the next source iter++; } // Now, do priority-based organization of audio sources. // All channels used, check priorities. // Find channel with lowest priority if (max_sourcep) { LLAudioChannel *channelp = getFreeChannel(max_priority); if (channelp) { //llinfos << "Replacing source in channel due to priority!" << llendl; max_sourcep->setChannel(channelp); channelp->setSource(max_sourcep); if (max_sourcep->isSyncSlave()) { // A sync slave, it doesn't start playing until it's synced up with the master. // Flag this channel as waiting for sync, and return true. channelp->setWaiting(true); } else { channelp->setWaiting(false); channelp->play(); } } } // 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(); // Update queued sounds (switch to next queued data if the current has finished playing) for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { // This is lame, instead of this I could actually iterate through all the sources // attached to each channel, since only those with active channels // can have anything interesting happen with their queue? (Maybe not true) LLAudioSource *sourcep = iter->second; if (!sourcep->mQueuedDatap || sourcep->isMuted()) { // Muted, or nothing queued, so we don't care. continue; } LLAudioChannel *channelp = sourcep->getChannel(); if (!channelp) { // This sound isn't playing, so we just process move the queue sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Reset the timer so the source doesn't die. sourcep->mAgeTimer.reset(); // Make sure we have the buffer set up if we just decoded the data if (sourcep->mCurrentDatap) { updateBufferForData(sourcep->mCurrentDatap); } // Actually play the associated data. sourcep->setupChannel(); channelp = sourcep->getChannel(); if (channelp) { channelp->updateBuffer(); sourcep->getChannel()->play(); } continue; } else { // Check to see if the current sound is done playing, or looped. if (!channelp->isPlaying()) { sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Reset the timer so the source doesn't die. sourcep->mAgeTimer.reset(); // Make sure we have the buffer set up if we just decoded the data if (sourcep->mCurrentDatap) { updateBufferForData(sourcep->mCurrentDatap); } // Actually play the associated data. sourcep->setupChannel(); channelp->updateBuffer(); sourcep->getChannel()->play(); } else if (sourcep->isLoop()) { // It's a loop, we need to check and see if we're done with it. if (channelp->mLoopedThisFrame) { sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Actually, should do a time sync so if we're a loop master/slave // we don't drift away. sourcep->setupChannel(); sourcep->getChannel()->play(); } } } } // Lame, update the channels AGAIN. // Update the channels to sync up with any changes that the source made, // such as changing what sound was playing. updateChannels(); // Hack! For now, just use a global sync master; LLAudioSource *sync_masterp = NULL; LLAudioChannel *master_channelp = NULL; F32 max_sm_priority = -1.f; for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; if (sourcep->isMuted()) { continue; } if (sourcep->isSyncMaster()) { if (sourcep->getPriority() > max_sm_priority) { sync_masterp = sourcep; master_channelp = sync_masterp->getChannel(); max_sm_priority = sourcep->getPriority(); } } } if (master_channelp && master_channelp->mLoopedThisFrame) { // Synchronize loop slaves with their masters // Update queued sounds (switch to next queued data if the current has finished playing) for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; if (!sourcep->isSyncSlave()) { // Not a loop slave, we don't need to do anything continue; } LLAudioChannel *channelp = sourcep->getChannel(); if (!channelp) { // Not playing, don't need to bother. continue; } if (!channelp->isPlaying()) { // Now we need to check if our loop master has just looped, and // start playback if that's the case. if (sync_masterp->getChannel()) { channelp->playSynced(master_channelp); channelp->setWaiting(false); } } } } // 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) { //llinfos << "Flushing unused buffer!" << llendl; 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); // Call this every frame, just in case we somehow // missed picking it up in all the places that can add // or request new data. startNextTransfer(); updateInternetStream(); }
void LLAudioEngine::startNextTransfer() { //llinfos << "LLAudioEngine::startNextTransfer()" << llendl; if (mCurrentTransfer.notNull() || getMuted()) { //llinfos << "Transfer in progress, aborting" << llendl; return; } // Get the ID for the next asset that we want to transfer. // Pick one in the following order: LLUUID asset_id; S32 i; LLAudioSource *asp = NULL; LLAudioData *adp = NULL; data_map::iterator data_iter; // Check all channels for currently playing sounds. F32 max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getCurrentData(); if (!adp) { continue; } if (!adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); } } // Check all channels for currently queued sounds. if (asset_id.isNull()) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } LLAudioSource *asp; asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getQueuedData(); if (!adp) { continue; } if (!adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); } } } // Check all live channels for other sounds (preloads). if (asset_id.isNull()) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } LLAudioSource *asp; asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) { LLAudioData *adp = data_iter->second; if (!adp) { continue; } if (!adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); } } } } // Check all sources if (asset_id.isNull()) { max_pri = -1.f; source_map::iterator source_iter; for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++) { asp = source_iter->second; if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getCurrentData(); if (adp && !adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); continue; } adp = asp->getQueuedData(); if (adp && !adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); continue; } for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) { LLAudioData *adp = data_iter->second; if (!adp) { continue; } if (!adp->hasLocalData() && adp->hasValidData()) { asset_id = adp->getID(); max_pri = asp->getPriority(); break; } } } } if (asset_id.notNull()) { llinfos << "Getting asset data for: " << asset_id << llendl; gAudiop->mCurrentTransfer = asset_id; gAudiop->mCurrentTransferTimer.reset(); gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, assetCallback, NULL); } else { //llinfos << "No pending transfers?" << llendl; } }
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(); }
void LLAudioEngine::startNextTransfer() { //LL_INFOS("AudioEngine") << "LLAudioEngine::startNextTransfer()" << LL_ENDL; if (getMuted()) { return; } else if(mCurrentTransferTimer.getElapsedTimeF32() <= .1f) { return; } else if(mCurrentTransfer && mCurrentTransfer->isInPreload()) { //Keep updating until it either errors out or completes. mCurrentTransfer->updateLoadState(); return; } else { mCurrentTransfer = NULL; } //Technically, mCurrentTransfer could end up pointing to an audiodata object that's already //being transmitted/decoded if such was spawned via needing it for playback immediately. //This will effectively block us from choosing a lower priority audiodata object until the //immediate ones are done, but it's not a real problem. // Get the ID for the next asset that we want to transfer. // Pick one in the following order: S32 i; LLAudioSource *asp = NULL; LLAudioData *adp = NULL; LLAudioData *cur_adp = NULL; data_map::iterator data_iter; // Check all channels for currently playing sounds. F32 max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getCurrentData(); if (!adp) { continue; } if (adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; } } // Check all channels for currently queued sounds. if (!cur_adp) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } LLAudioSource *asp; asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getQueuedData(); if (!adp) { continue; } if (adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; } } } // Check all live channels for other sounds (preloads). if (!cur_adp) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) { if (!mChannels[i]) { continue; } LLAudioSource *asp; asp = mChannels[i]->getSource(); if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) { LLAudioData *adp = data_iter->second; if (!adp) { continue; } if (adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; } } } } // Check all sources if (!cur_adp) { max_pri = -1.f; source_map::iterator source_iter; for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++) { asp = source_iter->second; if (!asp) { continue; } if (asp->getPriority() <= max_pri) { continue; } adp = asp->getCurrentData(); if (adp && adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; continue; } adp = asp->getQueuedData(); if (adp && adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; continue; } for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) { LLAudioData *adp = data_iter->second; if (!adp) { continue; } if (adp->isInPreload()) { max_pri = asp->getPriority(); cur_adp = adp; break; } } } } if (!cur_adp) { while(!mPreloadSystemList.empty()) { adp = getAudioData(mPreloadSystemList.front()); mPreloadSystemList.pop_front(); if(adp->isInPreload()) { cur_adp = adp; break; } } } else if(cur_adp) { std::list<LLUUID>::iterator it = std::find(mPreloadSystemList.begin(),mPreloadSystemList.end(),cur_adp->getID()); if(it != mPreloadSystemList.end()) mPreloadSystemList.erase(it); } if (cur_adp) { mCurrentTransfer = cur_adp; mCurrentTransferTimer.reset(); mCurrentTransfer->updateLoadState(); } else { //LL_INFOS("AudioEngine") << "No pending transfers?" << LL_ENDL; } }
void LLFloaterAvatarList::updateAvatarList() { //llinfos << "radar refresh: updating map" << llendl; // Check whether updates are enabled LLCheckboxCtrl* check = getChild<LLCheckboxCtrl>("update_enabled_cb"); if (check && !check->getValue()) { mUpdate = FALSE; refreshTracker(); return; } else { mUpdate = TRUE; } //moved to pipeline to prevent a crash //gPipeline.forAllVisibleDrawables(updateParticleActivity); //todo: make this less of a hacked up copypasta from dales 1.18. if(gAudiop != NULL) { LLAudioEngine::source_map::iterator iter; for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; LLUUID uuid = sourcep->getOwnerID(); LLAvatarListEntry *ent = getAvatarEntry(uuid); if ( ent ) { ent->setActivity(LLAvatarListEntry::ACTIVITY_SOUND); } } } LLVector3d mypos = gAgent.getPositionGlobal(); { std::vector<LLUUID> avatar_ids; std::vector<LLUUID> sorted_avatar_ids; std::vector<LLVector3d> positions; LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, F32_MAX); sorted_avatar_ids = avatar_ids; std::sort(sorted_avatar_ids.begin(), sorted_avatar_ids.end()); BOOST_FOREACH(std::vector<LLCharacter*>::value_type& iter, LLCharacter::sInstances) { LLUUID avid = iter->getID(); if (!std::binary_search(sorted_avatar_ids.begin(), sorted_avatar_ids.end(), avid)) { avatar_ids.push_back(avid); } } size_t i; size_t count = avatar_ids.size(); static LLCachedControl<bool> announce(gSavedSettings, "RadarChatKeys"); std::queue<LLUUID> announce_keys; for (i = 0; i < count; ++i) { std::string name; const LLUUID &avid = avatar_ids[i]; LLVector3d position; LLVOAvatar* avatarp = gObjectList.findAvatar(avid); if (avatarp) { // Skip if avatar is dead(what's that?) // or if the avatar is ourselves. // or if the avatar is a dummy if (avatarp->isDead() || avatarp->isSelf() || avatarp->mIsDummy) { continue; } // Get avatar data position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); name = avatarp->getFullname(); if (!LLAvatarNameCache::getPNSName(avatarp->getID(), name)) continue; //duped for lower section if (name.empty() || (name.compare(" ") == 0))// || (name.compare(gCacheName->getDefaultName()) == 0)) { if (!gCacheName->getFullName(avid, name)) //seems redudant with LLAvatarNameCache::getPNSName above... { continue; } } if (avid.isNull()) { //llinfos << "Key empty for avatar " << name << llendl; continue; } LLAvatarListEntry* entry = getAvatarEntry(avid); if (entry) { // Avatar already in list, update position F32 dist = (F32)(position - mypos).magVec(); entry->setPosition(position, (avatarp->getRegion() == gAgent.getRegion()), true, dist < 20.0, dist < 100.0); if(avatarp->isTyping())entry->setActivity(LLAvatarListEntry::ACTIVITY_TYPING); } else { // Avatar not there yet, add it if(announce && avatarp->getRegion() == gAgent.getRegion()) announce_keys.push(avid); mAvatars.push_back(LLAvatarListEntryPtr(new LLAvatarListEntry(avid, name, position))); } } else { if (i < positions.size()) { position = positions[i]; } else { continue; } if (!LLAvatarNameCache::getPNSName(avid, name)) { //name = gCacheName->getDefaultName(); continue; //prevent (Loading...) } LLAvatarListEntry* entry = getAvatarEntry(avid); if (entry) { // Avatar already in list, update position F32 dist = (F32)(position - mypos).magVec(); entry->setPosition(position, gAgent.getRegion()->pointInRegionGlobal(position), false, dist < 20.0, dist < 100.0); } else { if(announce && gAgent.getRegion()->pointInRegionGlobal(position)) announce_keys.push(avid); mAvatars.push_back(LLAvatarListEntryPtr(new LLAvatarListEntry(avid, name, position))); } } } //let us send the keys in a more timely fashion if (announce && !announce_keys.empty()) { // NOTE: This fragment is repeated in sendKey std::ostringstream ids; int transact_num = (int)gFrameCount; int num_ids = 0; while(!announce_keys.empty()) { LLUUID id = announce_keys.front(); announce_keys.pop(); ids << "," << id.asString(); ++num_ids; if (ids.tellp() > 200) { send_keys_message(transact_num, num_ids, ids.str()); num_ids = 0; ids.seekp(0); ids.str(""); } } if (num_ids > 0) send_keys_message(transact_num, num_ids, ids.str()); } }
void LLFloaterAvatarList::updateAvatarList() { //llinfos << "radar refresh: updating map" << llendl; // Check whether updates are enabled LLCheckboxCtrl* check = getChild<LLCheckboxCtrl>("update_enabled_cb"); if (check && !check->getValue()) { mUpdate = FALSE; refreshTracker(); return; } else { mUpdate = TRUE; } //moved to pipeline to prevent a crash //gPipeline.forAllVisibleDrawables(updateParticleActivity); //todo: make this less of a hacked up copypasta from dales 1.18. if(gAudiop != NULL) { LLAudioEngine::source_map::iterator iter; for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; LLUUID uuid = sourcep->getOwnerID(); LLAvatarListEntry *ent = getAvatarEntry(uuid); if ( ent ) { ent->setActivity(LLAvatarListEntry::ACTIVITY_SOUND); } } } LLVector3d mypos = gAgent.getPositionGlobal(); { std::vector<LLUUID> avatar_ids; std::vector<LLUUID> sorted_avatar_ids; std::vector<LLVector3d> positions; LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, F32_MAX); sorted_avatar_ids = avatar_ids; std::sort(sorted_avatar_ids.begin(), sorted_avatar_ids.end()); for (std::vector<LLCharacter*>::const_iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) { LLUUID avid = (*iter)->getID(); if (!std::binary_search(sorted_avatar_ids.begin(), sorted_avatar_ids.end(), avid)) { avatar_ids.push_back(avid); } } size_t i; size_t count = avatar_ids.size(); bool announce = gSavedSettings.getBOOL("RadarChatKeys"); std::queue<LLUUID> announce_keys; for (i = 0; i < count; ++i) { std::string name; std::string first; std::string last; const LLUUID &avid = avatar_ids[i]; LLVector3d position; LLVOAvatar* avatarp = gObjectList.findAvatar(avid); if (avatarp) { // Skip if avatar is dead(what's that?) // or if the avatar is ourselves. // or if the avatar is a dummy if (avatarp->isDead() || avatarp->isSelf() || avatarp->mIsDummy) { continue; } // Get avatar data position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); name = avatarp->getFullname(); // [Ansariel: Display name support] LLAvatarName avatar_name; if (LLAvatarNameCache::get(avatarp->getID(), &avatar_name)) { static LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0); switch (phoenix_name_system) { case 0 : name = avatar_name.getLegacyName(); break; case 1 : name = (avatar_name.mIsDisplayNameDefault ? avatar_name.mDisplayName : avatar_name.getCompleteName()); break; case 2 : name = avatar_name.mDisplayName; break; default : name = avatar_name.getLegacyName(); break; } first = avatar_name.mLegacyFirstName; last = avatar_name.mLegacyLastName; } else continue; // [/Ansariel: Display name support] //duped for lower section if (name.empty() || (name.compare(" ") == 0))// || (name.compare(gCacheName->getDefaultName()) == 0)) { if (!gCacheName->getFullName(avid, name)) //seems redudant with LLAvatarNameCache::get above... { continue; } } if (avid.isNull()) { //llinfos << "Key empty for avatar " << name << llendl; continue; } if (mAvatars.count(avid) > 0) { // Avatar already in list, update position F32 dist = (F32)(position - mypos).magVec(); mAvatars[avid].setPosition(position, (avatarp->getRegion() == gAgent.getRegion()), true, dist < 20.0, dist < 100.0); if(avatarp->isTyping())mAvatars[avid].setActivity(LLAvatarListEntry::ACTIVITY_TYPING); } else { // Avatar not there yet, add it LLAvatarListEntry entry(avid, name, position); if(announce && avatarp->getRegion() == gAgent.getRegion()) announce_keys.push(avid); mAvatars[avid] = entry; } } else { if (i < positions.size()) { position = positions[i]; } else { continue; } if (!gCacheName->getFullName(avid, name)) { //name = gCacheName->getDefaultName(); continue; //prevent (Loading...) } if (mAvatars.count(avid) > 0) { // Avatar already in list, update position F32 dist = (F32)(position - mypos).magVec(); mAvatars[avid].setPosition(position, gAgent.getRegion()->pointInRegionGlobal(position), false, dist < 20.0, dist < 100.0); } else { LLAvatarListEntry entry(avid, name, position); if(announce && gAgent.getRegion()->pointInRegionGlobal(position)) announce_keys.push(avid); mAvatars[avid] = entry; } } } //let us send the keys in a more timely fashion if(announce && !announce_keys.empty()) { std::ostringstream ids; int transact_num = (int)gFrameCount; int num_ids = 0; while(!announce_keys.empty()) { LLUUID id = announce_keys.front(); announce_keys.pop(); ids << "," << id.asString(); ++num_ids; if(ids.tellp() > 200) { gMessageSystem->newMessage("ScriptDialogReply"); gMessageSystem->nextBlock("AgentData"); gMessageSystem->addUUID("AgentID", gAgent.getID()); gMessageSystem->addUUID("SessionID", gAgent.getSessionID()); gMessageSystem->nextBlock("Data"); gMessageSystem->addUUID("ObjectID", gAgent.getID()); gMessageSystem->addS32("ChatChannel", -777777777); gMessageSystem->addS32("ButtonIndex", 1); gMessageSystem->addString("ButtonLabel",llformat("%d,%d", transact_num, num_ids) + ids.str()); gAgent.sendReliableMessage(); num_ids = 0; ids.seekp(0); ids.str(""); } } if(num_ids > 0) { gMessageSystem->newMessage("ScriptDialogReply"); gMessageSystem->nextBlock("AgentData"); gMessageSystem->addUUID("AgentID", gAgent.getID()); gMessageSystem->addUUID("SessionID", gAgent.getSessionID()); gMessageSystem->nextBlock("Data"); gMessageSystem->addUUID("ObjectID", gAgent.getID()); gMessageSystem->addS32("ChatChannel", -777777777); gMessageSystem->addS32("ButtonIndex", 1); gMessageSystem->addString("ButtonLabel",llformat("%d,%d", transact_num, num_ids) + ids.str()); gAgent.sendReliableMessage(); } } } // llinfos << "radar refresh: done" << llendl; expireAvatarList(); refreshAvatarList(); refreshTracker(); }