Example #1
0
void Core::updateControls(int cardId)
{
	settingsStr_->clear(MIXERS);
	settingsStr_->clearSwitches();
	const int soundCardId = (alsaWork_->cardExists(cardId)) ? cardId : alsaWork_->getFirstCardWithMixers();
	alsaWork_->setCurrentCard(soundCardId);
	settingsStr_->setCardId(soundCardId);
	settingsStr_->setList(MIXERS, alsaWork_->getVolumeMixers());
	settingsStr_->addMixerSwitch(alsaWork_->getSwitchList());
	const std::string newName = alsaWork_->getMixerName(settingsStr_->mixerId());
	if (mixerName_ != newName) {
		mixerName_ = newName;
		alsaWork_->setCurrentMixer(mixerName_);
	}
	if (!isPulse_) {
		volumeValue_ = alsaWork_->getAlsaVolume();
	}
#ifdef HAVE_PULSE
	else if (pulse_) {
		volumeValue_ = pulse_->getVolume();
	}
#endif
	m_signal_volume_changed(volumeValue_);
	updateTrayIcon(volumeValue_);
	m_signal_mixer_muted(getMuted());
	if(settingsDialog_) {
		blockAllSignals(true);
		settingsDialog_->updateMixers(settingsStr_->mixerList());
		settingsDialog_->updateSwitches(settingsStr_->switchList());
		blockAllSignals(false);
	}
}
void LLAudioEngine::setMasterGain(const F32 gain)
{
	mMasterGain = gain;
	F32 internal_gain = getMuted() ? 0.f : gain;
	if (internal_gain != mInternalGain)
	{
		mInternalGain = internal_gain;
		setInternalGain(mInternalGain);
	}
}
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.

	if (getMuted())
	{
		setInternalGain(0.f);
	}
	else
	{
		setInternalGain(getMasterGain());
	}

	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->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)
		{
			// 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->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();
}
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;
	}
}