diff options
| author | Roxie Linden <roxie@lindenlab.com> | 2010-05-04 14:03:30 -0700 | 
|---|---|---|
| committer | Roxie Linden <roxie@lindenlab.com> | 2010-05-04 14:03:30 -0700 | 
| commit | 2848d35e2cc72ba02817fc657fe248ccf91e3da8 (patch) | |
| tree | f64ff257516b37c95bdd02daf0702b428b4d4c13 /indra | |
| parent | 658ccc3e85487f9f24ff3b5926e60d6cce7f42e0 (diff) | |
re-merge e7cef87fae39 - EXT-6031 refactoring of voice volume representation
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/llvoiceclient.cpp | 98 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.h | 34 | ||||
| -rw-r--r-- | indra/newview/llvoicevivox.cpp | 114 | ||||
| -rw-r--r-- | indra/newview/llvoicevivox.h | 6 | 
4 files changed, 164 insertions, 88 deletions
| diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e067754e3e..70cff3644c 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -43,6 +43,10 @@  const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; +const F32 LLVoiceClient::VOLUME_MIN = 0.f; +const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f; +const F32 LLVoiceClient::VOLUME_MAX = 1.0f; +  std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)  {  	std::string result = "UNKNOWN"; @@ -795,23 +799,85 @@ LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()  void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)  { -	mSpeakersData[speaker_id] = volume; +	if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX)) +	{ +		mSpeakersData[speaker_id] = volume; + +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "Stored volume = " << volume <<  " for " << id << LL_ENDL; +	} +	else +	{ +		LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL; +		llassert(0); +	}  } -S32 LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id) +bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)  { -	// Return value of -1 indicates no level is stored for this speaker -	S32 ret_val = -1;  	speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);  	if (it != mSpeakersData.end())  	{ -		F32 f_val = it->second; -		// volume can amplify by as much as 4x! -		S32 ivol = (S32)(400.f * f_val * f_val); -		ret_val = llclamp(ivol, 0, 400); +		volume = it->second; + +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume <<  " for " << id << LL_ENDL; + +		return true;  	} -	return ret_val; + +	return false; +} + +void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id) +{ +	mSpeakersData.erase(speaker_id); + +	// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +	// LL_DEBUGS("Voice") << "Removing stored volume for  " << id << LL_ENDL; +} + +/* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in) +{ +	// Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB +	// from legacy characteristic composed of two square-curves +	// that intersect at volume_in = 0.5, volume_out = 0.56 + +	F32 volume_out = 0.f; +	volume_in = llclamp(volume_in, 0.f, 1.0f); + +	if (volume_in <= 0.5f) +	{ +		volume_out = volume_in * volume_in * 4.f * 0.56f; +	} +	else +	{ +		volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f; +	} + +	return volume_out; +} + +/* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in) +{ +	// Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB +	// to legacy characteristic composed of two square-curves +	// that intersect at volume_in = 0.56, volume_out = 0.5 + +	F32 volume_out = 0.f; +	volume_in = llclamp(volume_in, 0.f, 1.0f); + +	if (volume_in <= 0.56f) +	{ +		volume_out = sqrt(volume_in / (4.f * 0.56f)); +	} +	else +	{ +		volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f); +	} + +	return volume_out;  }  void LLSpeakerVolumeStorage::load() @@ -819,6 +885,8 @@ void LLSpeakerVolumeStorage::load()  	// load per-resident voice volume information  	std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME); +	LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL; +  	LLSD settings_llsd;  	llifstream file;  	file.open(filename); @@ -830,7 +898,10 @@ void LLSpeakerVolumeStorage::load()  	for (LLSD::map_const_iterator iter = settings_llsd.beginMap();  		iter != settings_llsd.endMap(); ++iter)  	{ -		mSpeakersData.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal())); +		// Maintain compatibility with 1.23 non-linear saved volume levels +		F32 volume = transformFromLegacyVolume((F32)iter->second.asReal()); + +		storeSpeakerVolume(LLUUID(iter->first), volume);  	}  } @@ -845,9 +916,14 @@ void LLSpeakerVolumeStorage::save()  		std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);  		LLSD settings_llsd; +		LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL; +  		for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter)  		{ -			settings_llsd[iter->first.asString()] = iter->second; +			// Maintain compatibility with 1.23 non-linear saved volume levels +			F32 volume = transformToLegacyVolume(iter->second); + +			settings_llsd[iter->first.asString()] = volume;  		}  		llofstream file; diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index f1a7d3dbec..5d6bcf4a72 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -272,7 +272,11 @@ public:  	const LLVoiceVersionInfo getVersion(); -static const F32 OVERDRIVEN_POWER_LEVEL; +	static const F32 OVERDRIVEN_POWER_LEVEL; + +	static const F32 VOLUME_MIN; +	static const F32 VOLUME_DEFAULT; +	static const F32 VOLUME_MAX;  	void updateSettings(); // call after loading settings and whenever they change @@ -406,31 +410,34 @@ protected:  /**   * Speaker volume storage helper class   **/ -  class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage>  {  	LOG_CLASS(LLSpeakerVolumeStorage);  public:  	/** -	 * Sets internal voluem level for specified user. +	 * Stores volume level for specified user.  	 * -	 * @param[in] speaker_id - LLUUID of user to store volume level for -	 * @param[in] volume - external volume level to be stored for user. +	 * @param[in] speaker_id - LLUUID of user to store volume level for. +	 * @param[in] volume - volume level to be stored for user.  	 */  	void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume);  	/** -	 * Gets stored external volume level for specified speaker. +	 * Gets stored volume level for specified speaker  	 * -	 * If specified user is not found default level will be returned. It is equivalent of  -	 * external level 0.5 from the 0.0..1.0 range. -	 * Default external level is calculated as: internal = 400 * external^2 -	 * Maps 0.0 to 1.0 to internal values 0-400 with default 0.5 == 100 +	 * @param[in] speaker_id - LLUUID of user to retrieve volume level for. +	 * @param[out] volume - set to stored volume if found, otherwise unmodified. +	 * @return - true if a stored volume is found. +	 */ +	bool getSpeakerVolume(const LLUUID& speaker_id, F32& volume); + +	/** +	 * Removes stored volume level for specified user.  	 * -	 * @param[in] speaker_id - LLUUID of user to get his volume level +	 * @param[in] speaker_id - LLUUID of user to remove.  	 */ -	S32 getSpeakerVolume(const LLUUID& speaker_id); +	void removeSpeakerVolume(const LLUUID& speaker_id);  private:  	friend class LLSingleton<LLSpeakerVolumeStorage>; @@ -442,6 +449,9 @@ private:  	void load();  	void save(); +	static F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in); +	static F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in); +  	typedef std::map<LLUUID, F32> speaker_data_map_t;  	speaker_data_map_t mSpeakersData;  }; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a7efc49c67..6986ca0a90 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -78,6 +78,8 @@  #define USE_SESSION_GROUPS 0 +const F32 VOLUME_SCALE_VIVOX = 0.01f; +  const F32 SPEAKING_TIMEOUT = 1.f;  static const std::string VOICE_SERVER_TYPE = "Vivox"; @@ -1476,9 +1478,10 @@ void LLVivoxVoiceClient::stateMachine()  					enforceTether();  				} -				// Send an update if the ptt state has changed (which shouldn't be able to happen that often -- the user can only click so fast) -				// or every 10hz, whichever is sooner. -				if((mAudioSession && mAudioSession->mVolumeDirty) || mPTTDirty || mSpeakerVolumeDirty || mUpdateTimer.hasExpired()) +				// Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often +				// -- the user can only click so fast) or every 10hz, whichever is sooner. +				// Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged. +				if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())  				{  					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);  					sendPositionalUpdate(); @@ -2475,11 +2478,12 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)  		stream << "</Request>\n\n\n";  	}	 -	if(mAudioSession && mAudioSession->mVolumeDirty) +	if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))  	{  		participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();  		mAudioSession->mVolumeDirty = false; +		mAudioSession->mMuteDirty = false;  		for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)  		{ @@ -2490,7 +2494,8 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)  				// Can't set volume/mute for yourself  				if(!p->mIsSelf)  				{ -					int volume = 56; // nominal default value +					// scale from the range 0.0-1.0 to vivox volume in the range 0-100 +					S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX);  					bool mute = p->mOnMuteList;  					if(p->mUserVolume != -1) @@ -2514,10 +2519,15 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)  						// If we want the user to be muted, set their volume to 0 as well.  						// This isn't perfect, but it will at least reduce their volume to a minimum.  						volume = 0; +						// Mark the current volume level as set to prevent incoming events +						// changing it to 0, so that we can return to it when unmuting. +						p->mVolumeSet = true;  					}  					if(volume == 0) +					{  						mute = true; +					}  					LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL; @@ -3671,15 +3681,12 @@ void LLVivoxVoiceClient::participantUpdatedEvent(  				participant->mPower = 0.0f;  			} -			// *HACK: Minimal hack to fix EXT-6508, ignore the incoming volume if it is zero. -			// This happens because we send volume zero to Vivox when someone is muted, -			// Vivox then send it back to us, overwriting the previous volume. -			// Remove this hack once volume refactoring from EXT-6031 is applied. -			if (volume != 0) -			  { -			    participant->mVolume = volume; -			  } -  +			// Ignore incoming volume level if it has been explicitly set, or there +			//  is a volume or mute change pending. +			if ( !participant->mVolumeSet && !participant->mVolumeDirty) +			{ +				participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX; +			}  			// *HACK: mantipov: added while working on EXT-3544                                                                                     			/*                                                                                                                                     @@ -4089,7 +4096,7 @@ LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :  	 mIsModeratorMuted(false),   	 mLastSpokeTimestamp(0.f),   	 mPower(0.f),  -	 mVolume(-1),  +	 mVolume(LLVoiceClient::VOLUME_DEFAULT),   	 mOnMuteList(false),   	 mUserVolume(-1),   	 mVolumeDirty(false),  @@ -4141,7 +4148,7 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti  				result->mAvatarID = id;  				if(result->updateMuteState()) -					mVolumeDirty = true; +					mMuteDirty = true;  			}  			else  			{ @@ -4153,7 +4160,11 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti  		mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result)); -		result->mUserVolume = LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID); +		if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume)) +		{ +			result->mVolumeDirty = true; +			mVolumeDirty = true; +		}  		LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;  	} @@ -5351,51 +5362,21 @@ BOOL LLVivoxVoiceClient::getOnMuteList(const LLUUID& id)  	return result;  } -// External accessiors. Maps 0.0 to 1.0 to internal values 0-400 with .5 == 100 -// internal = 400 * external^2 +// External accessors.  F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id)  { -	F32 result = 0.0f; +       // Minimum volume will be returned for users with voice disabled +       F32 result = LLVoiceClient::VOLUME_MIN; -	participantState *participant = findParticipantByID(id); -	if(participant) +        participantState *participant = findParticipantByID(id); +        if(participant)  	{ -		S32 ires = 100; // nominal default volume -		 -		if(participant->mIsSelf) -		{ -			// Always make it look like the user's own volume is set at the default. -		} -		else if(participant->mUserVolume != -1) -		{ -			// Use the internal volume -			ires = participant->mUserVolume; -			 -			// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//			LL_DEBUGS("Voice") << "mapping from mUserVolume " << ires << LL_ENDL; -		} -		else if(participant->mVolume != -1) -		{ -			// Map backwards from vivox volume  +		result = participant->mVolume; -			// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//			LL_DEBUGS("Voice") << "mapping from mVolume " << participant->mVolume << LL_ENDL; - -			if(participant->mVolume < 56) -			{ -				ires = (participant->mVolume * 100) / 56; -			} -			else -			{ -				ires = (((participant->mVolume - 56) * 300) / (100 - 56)) + 100; -			} -		} -		result = sqrtf(((F32)ires) / 400.f); +		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. +		// LL_DEBUGS("Voice") << "mVolume = " << result <<  " for " << id << LL_ENDL;  	} -	// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging. -//	LL_DEBUGS("Voice") << "returning " << result << LL_ENDL; -  	return result;  } @@ -5404,16 +5385,23 @@ void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume)  	if(mAudioSession)  	{  		participantState *participant = findParticipantByID(id); -		if (participant) +		if (participant && !participant->mIsSelf)  		{ -			// store this volume setting for future sessions -			LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume); -			// volume can amplify by as much as 4x! -			S32 ivol = (S32)(400.f * volume * volume); -			participant->mUserVolume = llclamp(ivol, 0, 400); -			participant->mVolumeDirty = TRUE; -			mAudioSession->mVolumeDirty = TRUE; +			if (!is_approx_equal(volume, LLVoiceClient::VOLUME_DEFAULT)) +			{ +				// Store this volume setting for future sessions if it has been +				// changed from the default +				LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume); +			} +			else +			{ +				// Remove stored volume setting if it is returned to the default +				LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id); +			} +			participant->mVolume = llclamp(volume, LLVoiceClient::VOLUME_MIN, LLVoiceClient::VOLUME_MAX); +			participant->mVolumeDirty = true; +			mAudioSession->mVolumeDirty = true;  		}  	}  } diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 10577254e8..e4e0b87ad0 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -260,7 +260,7 @@ protected:  	public:  		participantState(const std::string &uri); -		bool updateMuteState(); +	        bool updateMuteState();	// true if mute state has changed  		bool isAvatar();  		std::string mURI; @@ -270,13 +270,14 @@ protected:  		LLFrameTimer mSpeakingTimeout;  		F32	mLastSpokeTimestamp;  		F32 mPower; -		int mVolume; +		F32 mVolume;  		std::string mGroupID;  		int mUserVolume;  		bool mPTT;  		bool mIsSpeaking;  		bool mIsModeratorMuted;  		bool mOnMuteList;		// true if this avatar is on the user's mute list (and should be muted) +	       bool mVolumeSet;		// true if incoming volume messages should not change the volume  		bool mVolumeDirty;		// true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)  		bool mAvatarIDValid;  		bool mIsSelf; @@ -333,6 +334,7 @@ protected:  		// Set to true when the mute state of someone in the participant list changes.  		// The code will have to walk the list to find the changed participant(s).  		bool		mVolumeDirty; +	        bool		mMuteDirty;  		bool		mParticipantsChanged;  		participantMap mParticipantsByURI; | 
