Anonymous avatar Anonymous committed c9cf317

EXT-7138 WIP Use fixed time of day for expiry of Voice Fonts, as the timestamp from Vivox is incorrect.

Will need the correct time specifying as VOICE_FONT_EXPIRY_TIME when know what it is from Vivox.
Enforce expiry times rather than just relying on the flag from Vivox to avoid ambiguity.
Only set expiry timers on adding new fonts, or if the expiry time has changed, to avoid unnecessary notifications.

Comments (0)

Files changed (2)

indra/newview/llvoicevivox.cpp

 // blocked is VERY rare and it's better to sacrifice response time in this situation for the sake of stability.
 const int MAX_NORMAL_JOINING_SPATIAL_NUM = 50;
 
-// How often to check for expired voice fonts
-const F32 VOICE_FONT_EXPIRY_INTERVAL = 1.f;
-
-// Maximum length of capture buffer recordings
-const F32 CAPTURE_BUFFER_MAX_TIME = 15.f;
+// How often to check for expired voice fonts in seconds
+const F32 VOICE_FONT_EXPIRY_INTERVAL = 10.f;
+// Time of day at which Vivox expires voice font subscriptions.
+// Used to replace the time portion of received expiry timestamps.
+static const std::string VOICE_FONT_EXPIRY_TIME = "T05:00:00Z";
+
+// Maximum length of capture buffer recordings in seconds.
+const F32 CAPTURE_BUFFER_MAX_TIME = 10.f;
 
 
 static int scale_mic_volume(float volume)
 								 const std::string &name,
 								 const std::string &description,
 								 const LLDate &expiration_date,
-								 const bool has_expired,
+								 bool has_expired,
 								 const S32 font_type,
 								 const S32 font_status,
 								 const bool template_font)
 	voice_font_map_t::iterator iter = font_map.find(font_id);
 	bool new_font = (iter == font_map.end());
 
+	// Override the has_expired flag if we have passed the expiration_date as a double check.
+	if (expiration_date.secondsSinceEpoch() < (LLDate::now().secondsSinceEpoch() + VOICE_FONT_EXPIRY_INTERVAL))
+	{
+		has_expired = true;
+	}
+
 	if (has_expired)
 	{
+		LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "")
+		<< expiration_date.asString() << " " << font_id
+		<< " (" << font_index << ") " << name << LL_ENDL;
+
 		// Remove existing session fonts that have expired since we last saw them.
-		if (!new_font)
-		{
-			LL_DEBUGS("Voice") << "Expired " << (template_font ? "Template " : "")
-			<< expiration_date.asString() << " " << font_id
-			<< " (" << font_index << ") " << name << LL_ENDL;
-
-			if (!template_font)
-			{
-				deleteVoiceFont(font_id);
-			}
+		if (!new_font && !template_font)
+		{
+			deleteVoiceFont(font_id);
 		}
 		return;
 	}
 		// Use the description for the human readable name if available, as the
 		// "name" may be a UUID.
 		font->mName = description.empty() ? name : description;
-		font->mExpirationDate = expiration_date;
 		font->mFontType = font_type;
 		font->mFontStatus = font_status;
 
+		// If the font is new or the expiration date has changed the expiry timers need updating.
+		if (!template_font && (new_font || font->mExpirationDate != expiration_date))
+		{
+			font->mExpirationDate = expiration_date;
+
+			// Set the expiry timer to trigger a notification when the voice font can no longer be used.
+			font->mExpiryTimer.start();
+			font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch() - VOICE_FONT_EXPIRY_INTERVAL);
+
+			// Set the warning timer to some interval before actual expiry.
+			S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime");
+			if (warning_time != 0)
+			{
+				font->mExpiryWarningTimer.start();
+				F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time);
+				font->mExpiryWarningTimer.setExpiryAt(expiry_time - VOICE_FONT_EXPIRY_INTERVAL);
+			}
+			else
+			{
+				// Disable the warning timer.
+				font->mExpiryWarningTimer.stop();
+			}
+
+			 // Only flag new session fonts after the first time we have fetched the list.
+			if (mVoiceFontsReceived)
+			{
+				font->mIsNew = true;
+				mVoiceFontsNew = true;
+			}
+		}
+
 		LL_DEBUGS("Voice") << (template_font ? "Template " : "")
 			<< font->mExpirationDate.asString() << " " << font->mID
 			<< " (" << font->mFontIndex << ") " << name << LL_ENDL;
 
-		// Set the expiry timer to trigger a notification when the voice font can no longer be used.
-		font->mExpiryTimer.start();
-		font->mExpiryTimer.setExpiryAt(expiration_date.secondsSinceEpoch());
-
-		if (font->mExpiryTimer.hasExpired())
-		{
-			// Should never happen, but check anyway.
-			LL_DEBUGS("Voice") << "Voice font " << font->mID
-				<< " expired " << font->mExpirationDate.asString()
-				<< " but is not marked expired!" << LL_ENDL;
-		}
-
-		// Set the warning timer to some interval before actual expiry.
-		S32 warning_time = gSavedSettings.getS32("VoiceEffectExpiryWarningTime");
-		if (warning_time != 0)
-		{
-			font->mExpiryWarningTimer.start();
-			F64 expiry_time = (expiration_date.secondsSinceEpoch() - (F64)warning_time);
-			font->mExpiryWarningTimer.setExpiryAt(expiry_time);
-		}
-		else
-		{
-			// Disable the warning timer.
-			font->mExpiryWarningTimer.stop();
-		}
-
-		 // Only flag new session fonts.
-		if (!template_font && mVoiceFontsReceived && new_font)
-		{
-			font->mIsNew = true;
-			mVoiceFontsNew = true;
-		}
-
 		if (new_font)
 		{
 			font_map.insert(voice_font_map_t::value_type(font->mID, font));
 				setVoiceEffect(LLUUID::null);
 				expired_in_use = true;
 			}
+
+			LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " has expired." << LL_ENDL;
 			deleteVoiceFont(voice_font->mID);
 			have_expired = true;
 		}
 		// Check for voice fonts that will expire in less that the warning time
 		if (warning_timer.getStarted() && warning_timer.hasExpired())
 		{
+			LL_DEBUGS("Voice") << "Voice Font " << voice_font->mName << " will expire soon." << LL_ENDL;
 			will_expire = true;
 			warning_timer.stop();
 		}
 		}
 		else if (!stricmp("ExpirationDate", tag))
 		{
-			expirationDate = vivoxTimeStampToLLDate(string);
+			expirationDate = expiryTimeStampToLLDate(string);
 		}
 		else if (!stricmp("Expired", tag))
 		{
 
 // --------------------------------------------------------------------------------
 
-LLDate LLVivoxProtocolParser::vivoxTimeStampToLLDate(const std::string& vivox_ts)
-{
-	LLDate ts;
-
-	// First check to see if it actually already is an ISO 8601 date that
-	// LLDate::fromString() can parse.
-	// In case the format miraculously changes in future ;)
-	if (ts.fromString(vivox_ts))
-	{
-		return ts;
-	}
-
-	std::string time_stamp = vivox_ts;
-
-	// Vivox's format is missing a T from being standard ISO 8601,
-	// so add it instead of the only space after the date.
-	LLStringUtil::replaceChar(time_stamp, ' ', 'T');
-
-	// LLDate can't handle offsets from UTC, so remove it, and add a Z
-	time_stamp = time_stamp.substr(0, time_stamp.length() - 3);
-	time_stamp += "Z";
-
-	ts.fromString(time_stamp);
-	if(!ts.fromString(time_stamp))
-	{
-		LL_WARNS_ONCE("VivoxProtocolParser") << "Failed to parse Vivox timestamp: "
-					<< vivox_ts << " to ISO 8601 date: " << time_stamp << LL_ENDL;
-		return LLDate();
-	}
-
-	return ts;
+LLDate LLVivoxProtocolParser::expiryTimeStampToLLDate(const std::string& vivox_ts)
+{
+	// *HACK: Vivox reports the time incorrectly. LLDate also only parses a
+	// subset of valid ISO 8601 dates (only handles Z, not offsets).
+	// So just use the date portion and fix the time here.
+	std::string time_stamp = vivox_ts.substr(0, 10);
+	time_stamp += VOICE_FONT_EXPIRY_TIME;
+
+	LL_DEBUGS("VivoxProtocolParser") << "Vivox timestamp " << vivox_ts << " modified to: " << time_stamp << LL_ENDL;
+
+	return LLDate(time_stamp);
 }
 
 // --------------------------------------------------------------------------------

indra/newview/llvoicevivox.h

 					  const std::string &name,
 					  const std::string &description,
 					  const LLDate &expiration_date,
-					  const bool has_expired,
+					  bool  has_expired,
 					  const S32 font_type,
 					  const S32 font_status,
 					  const bool template_font = false);
 	void			StartTag(const char *tag, const char **attr);
 	void			EndTag(const char *tag);
 	void			CharData(const char *buffer, int length);
-	LLDate			vivoxTimeStampToLLDate(const std::string& vivox_ts);
+	LLDate			expiryTimeStampToLLDate(const std::string& vivox_ts);
 };
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.