diff options
| -rw-r--r-- | indra/llwindow/llwindowsdl.cpp | 12 | ||||
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 2 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.cpp | 258 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.h | 11 | 
4 files changed, 172 insertions, 111 deletions
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 1f705f9e60..efa0110f8b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -2543,6 +2543,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()  	// Use libfontconfig to find us a nice ordered list of fallback fonts  	// specific to this system.  	std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); +	const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them  	// Our 'ideal' font properties which define the sorting results.  	// slant=0 means Roman, index=0 means the first face in a font file  	// (the one we actually use), weight=80 means medium weight, @@ -2558,7 +2559,6 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()  	std::vector<std::string> rtns;  	FcFontSet *fs = NULL;  	FcPattern *sortpat = NULL; -	int font_count = 0;  	llinfos << "Getting system font list from FontConfig..." << llendl; @@ -2602,12 +2602,13 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()  		FcPatternDestroy(sortpat);  	} +	int found_font_count = 0;  	if (fs)  	{  		// Get the full pathnames to the fonts, where available,  		// which is what we really want. -		int i; -		for (i=0; i<fs->nfont; ++i) +		found_font_count = fs->nfont; +		for (int i=0; i<fs->nfont; ++i)  		{  			FcChar8 *filename;  			if (FcResultMatch == FcPatternGetString(fs->fonts[i], @@ -2616,7 +2617,8 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()  			    && filename)  			{  				rtns.push_back(std::string((const char*)filename)); -				++font_count; +				if (rtns.size() >= max_font_count_cutoff) +					break; // hit limit  			}  		}  		FcFontSetDestroy (fs); @@ -2629,7 +2631,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList()  	{  		lldebugs << "  file: " << *it << llendl;  	} -	llinfos << "Using " << font_count << " system font(s)." << llendl; +	llinfos << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << llendl;  	rtns.push_back(final_fallback);  	return rtns; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9f474a39bc..73fb24e4eb 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10369,7 +10369,7 @@        <key>Type</key>        <string>Boolean</string>        <key>Value</key> -      <integer>1</integer> +      <integer>0</integer>      </map>      <key>VivoxDebugLevel</key>      <map> diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e8fdccf30e..d8319f3cc3 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -87,6 +87,12 @@  static bool sConnectingToAgni = false;  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; + +const F32 VOLUME_SCALE_VIVOX = 0.01f; +  const F32 SPEAKING_TIMEOUT = 1.f;  const int VOICE_MAJOR_VERSION = 1; @@ -1112,24 +1118,28 @@ class LLSpeakerVolumeStorage : public LLSingleton<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 (vivox) 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 (vivox) volume level for specified speaker and -	 * transforms it into internal (viewer) level. +	 * Gets stored volume level for specified speaker  	 * -	 * If specified user is not found -1 will be returned. -	 * Internal level is calculated as: internal = 400 * external^2 -	 * Maps 0.0 to 1.0 to internal values 0-400 +	 * @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>; @@ -1141,6 +1151,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;  }; @@ -1159,23 +1172,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 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 ret_val; + +	return volume_out;  }  void LLSpeakerVolumeStorage::load() @@ -1183,6 +1258,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); @@ -1194,7 +1271,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);  	}  } @@ -1209,9 +1289,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; @@ -2420,9 +2505,10 @@ void LLVoiceClient::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(); @@ -3417,38 +3503,26 @@ void LLVoiceClient::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++)  		{  			participantState *p = iter->second; -			 +  			if(p->mVolumeDirty)  			{  				// 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) -					{ -						// scale from user volume in the range 0-400 (with 100 as "normal") to vivox volume in the range 0-100 (with 56 as "normal") -						if(p->mUserVolume < 100) -							volume = (p->mUserVolume * 56) / 100; -						else -							volume = (((p->mUserVolume - 100) * (100 - 56)) / 300) + 56; -					} -					else if(p->mVolume != -1) -					{ -						// Use the previously reported internal volume (comes in with a ParticipantUpdatedEvent) -						volume = p->mVolume; -					} -										  					if(mute)  					{ @@ -3456,10 +3530,16 @@ void LLVoiceClient::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; @@ -4600,16 +4680,13 @@ void LLVoiceClient::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) +			// 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 = volume; +				participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;  			} -			  			// *HACK: mantipov: added while working on EXT-3544  			/*  			Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE  @@ -4993,7 +5070,7 @@ void LLVoiceClient::muteListChanged()  			// Check to see if this participant is on the mute list already  			if(p->updateMuteState()) -				mAudioSession->mVolumeDirty = true; +				mAudioSession->mMuteDirty = true;  		}  	}  } @@ -5016,10 +5093,10 @@ LLVoiceClient::participantState::participantState(const std::string &uri) :  	 mIsModeratorMuted(false),   	 mLastSpokeTimestamp(0.f),   	 mPower(0.f),  -	 mVolume(-1),  -	 mOnMuteList(false),  -	 mUserVolume(-1),  -	 mVolumeDirty(false),  +	 mVolume(VOLUME_DEFAULT), +	 mOnMuteList(false), +	 mVolumeSet(false), +	 mVolumeDirty(false),  	 mAvatarIDValid(false),  	 mIsSelf(false)  { @@ -5068,7 +5145,7 @@ LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(con  				result->mAvatarID = id;  				if(result->updateMuteState()) -					mVolumeDirty = true; +					mMuteDirty = true;  			}  			else  			{ @@ -5080,8 +5157,7 @@ LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(con  		mParticipantsByUUID.insert(participantUUIDMap::value_type(&(result->mAvatarID), result)); -		result->mUserVolume = LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID); -		if (result->mUserVolume != -1) +		if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))  		{  			result->mVolumeDirty = true;  			mVolumeDirty = true; @@ -6279,51 +6355,21 @@ BOOL LLVoiceClient::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 LLVoiceClient::getUserVolume(const LLUUID& id)  { -	F32 result = 0.0f; +	// Minimum volume will be returned for users with voice disabled +	F32 result = VOLUME_MIN;  	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  - -			// 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; +		result = participant->mVolume; -			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;  } @@ -6332,16 +6378,23 @@ void LLVoiceClient::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); +			if (!is_approx_equal(volume, 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); +			} -			// 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; +			participant->mVolume = llclamp(volume, VOLUME_MIN, VOLUME_MAX); +			participant->mVolumeDirty = true; +			mAudioSession->mVolumeDirty = true;  		}  	}  } @@ -6482,6 +6535,7 @@ LLVoiceClient::sessionState::sessionState() :  	mVoiceEnabled(false),  	mReconnect(false),  	mVolumeDirty(false), +	mMuteDirty(false),  	mParticipantsChanged(false)  {  } diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index aaacab69e0..a29c386182 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -101,6 +101,10 @@ class LLVoiceClient: public LLSingleton<LLVoiceClient>  		static 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  		void getCaptureDevicesSendMessage(); @@ -269,7 +273,7 @@ static	void updatePosition(void);  		public:  			participantState(const std::string &uri); -			bool updateMuteState(); +			bool updateMuteState();	// true if mute state has changed  			bool isAvatar();  			std::string mURI; @@ -279,13 +283,13 @@ static	void updatePosition(void);  			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; @@ -349,6 +353,7 @@ static	void updatePosition(void);  			// 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;  | 
