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 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();
}
Пример #3
0
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;
	}
}