diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index 8ac28daeb8..b1d7eac943 100644
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -558,6 +558,12 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL;
}
+ if (raw_image->isBufferInvalid())
+ {
+ setLastError("Invalid input, no buffer");
+ return false;
+ }
+
setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);
U8 magic[14];
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 1e60713b6d..5cccc701a4 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -329,6 +329,12 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_
{
llassert_always(raw_image);
+ if (raw_image->isBufferInvalid())
+ {
+ setLastError("Invalid input, no buffer");
+ return false;
+ }
+
S32 ncomponents = raw_image->getComponents();
EFileFormat format;
switch (ncomponents)
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index 807e9c70d2..92374e88f7 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -492,6 +492,12 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
resetLastError();
+ if (raw_image->isBufferInvalid())
+ {
+ setLastError("Invalid input, no buffer");
+ return false;
+ }
+
LLImageDataSharedLock lockIn(raw_image);
LLImageDataLock lockOut(this);
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index af7d6c0610..2bd6239dd3 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -956,6 +956,12 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
{
+ if (raw_image.isBufferInvalid())
+ {
+ base.setLastError("Invalid input, no buffer");
+ return false;
+ }
+
JPEG2KEncode encode(comment_text, reversible);
bool encoded = encode.encode(raw_image, base);
if (!encoded)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 1444e36179..e48eabb5c0 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -687,6 +687,12 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
bool vflip = true;
bool hflip = false;
+ if (raw_image.isBufferInvalid())
+ {
+ base.setLastError("Invalid input, no buffer");
+ return false;
+ }
+
try
{
// Set up input image files
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index dfe352e4d6..81dea9bef2 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -904,12 +904,12 @@ void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable)
// set_enabled shouldn't be done on the worker thread.
if (mPeerConnection)
{
+ mPeerConnection->SetAudioRecording(enable);
auto senders = mPeerConnection->GetSenders();
for (auto &sender : senders)
{
sender->track()->set_enabled(enable);
}
- mPeerConnection->SetAudioRecording(enable);
}
}
@@ -964,6 +964,9 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
{
if (mPeerConnection)
{
+ // SetAudioRecording must be called before enabling/disabling tracks.
+ mPeerConnection->SetAudioRecording(enable);
+
auto senders = mPeerConnection->GetSenders();
RTC_LOG(LS_INFO) << __FUNCTION__ << (mMute ? "disabling" : "enabling") << " streams count " << senders.size();
@@ -982,7 +985,6 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
track->set_enabled(enable);
}
}
- mPeerConnection->SetAudioRecording(enable);
}
});
}
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index d4e7108c2e..96d3f43068 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1010,7 +1010,7 @@ void LLWindowWin32::close()
// Restore gamma to the system values.
restoreGamma();
- LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
+ LL_INFOS("Window") << "Destroying Window Thread" << LL_ENDL;
if (sWindowHandleForMessageBox == mWindowHandle)
{
@@ -5055,7 +5055,7 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{
if (mQueue->isClosed())
{
- LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
+ LL_WARNS("Window") << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
return false;
}
@@ -5064,6 +5064,11 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{
ShowWindow(mWindowHandleThrd, SW_HIDE);
}
+ else
+ {
+ LL_WARNS("Window") << "Tried to hide window, but Win32 window handle is NULL." << LL_ENDL;
+ return false;
+ }
mGLReady = false;
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp
index f11593850e..cca1fa4fd1 100644
--- a/indra/llxml/llcontrol.cpp
+++ b/indra/llxml/llcontrol.cpp
@@ -165,7 +165,10 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
{
if ((persist != PERSIST_NO) && mComment.empty())
{
- LL_ERRS() << "Must supply a comment for control " << mName << ". Please perform a clean installation!" << LL_ENDL;
+ // File isn't actually missing, but something is wrong with it
+ // so the main point is to warn user to reinstall
+ LLError::LLUserWarningMsg::showMissingFiles();
+ LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL;
}
//Push back versus setValue'ing here, since we don't want to call a signal yet
mValues.push_back(initial);
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 0ee843cc60..b26a34e470 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-7.2.0
+7.2.1
diff --git a/indra/newview/fschathistory.cpp b/indra/newview/fschathistory.cpp
index 07566c2f1f..9ca8678b24 100644
--- a/indra/newview/fschathistory.cpp
+++ b/indra/newview/fschathistory.cpp
@@ -1087,7 +1087,7 @@ protected:
menu->setItemEnabled("Chat History", false);
menu->setItemEnabled("Add Contact Set", false);
menu->setItemEnabled("Invite Group", false);
- menu->setItemEnabled("Zoom In", false);
+ menu->setItemEnabled("Zoom In", true);
menu->setItemEnabled("track", false);
menu->setItemEnabled("Share", false);
menu->setItemEnabled("Pay", false);
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 5b6729008f..2b8d1f8ec5 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -989,7 +989,7 @@ protected:
menu->setItemEnabled("Voice Call", false);
menu->setItemEnabled("Chat History", false);
menu->setItemEnabled("Invite Group", false);
- menu->setItemEnabled("Zoom In", false);
+ menu->setItemEnabled("Zoom In", true);
menu->setItemEnabled("Share", false);
menu->setItemEnabled("Pay", false);
menu->setItemEnabled("Block Unblock", false);
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 0e58ab3ada..1a05536316 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -437,7 +437,9 @@ void LLFloaterImagePreview::onBtnOK()
}
else
{
- LLNotificationsUtil::add("ErrorEncodingImage");
+ LLSD args;
+ args["REASON"] = LLImage::getLastThreadError();
+ LLNotificationsUtil::add("ErrorEncodingImage", args);
LL_WARNS() << "Error encoding image" << LL_ENDL;
}
}
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index fcb3176ecc..75ed348ca0 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -1544,6 +1544,10 @@ bool LLFloaterIMContainer::enableContextMenuItem(const std::string& item, uuid_v
// Beyond that point, if only the user agent is selected, everything is disabled
if (is_single_select && (single_id == gAgentID))
{
+ if ("can_zoom_in" == item)
+ {
+ return true;
+ }
if (is_moderator_option)
{
return enableModerateContextMenuItem(item, true);
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 5ac0102fe6..d9b016f8e2 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -766,7 +766,8 @@ bool LLFloaterPreference::postBuild()
// Prefer FS-specific Discord implementation
//#ifndef LL_DISCORD
-// getChild("privacy_tab_container")->childDisable("privacy_preferences_discord");
+// LLPanel* panel = getChild("privacy_preferences_discord");
+// getChild("privacy_tab_container")->removeTabPanel(panel);
//#endif
//
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 7542011523..6706c2aa48 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -543,8 +543,8 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list& m
}
// If we got here, we managed to stat the file.
- // Open the file to read
- LLFILE* fptr = LLFile::fopen(log_file_name, "r"); /*Flawfinder: ignore*/
+ // Open the file to read in binary mode to prevent interpreting other characters as EOF
+ LLFILE* fptr = LLFile::fopen(log_file_name, "rb"); /*Flawfinder: ignore*/
if (!fptr)
{ // Ok, this is strange but not really tragic in the big picture of things
LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL;
@@ -1337,7 +1337,7 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list
- fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r");
+ fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "rb");
if (fptr)
{
fclose(fptr);
LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name));
}
- fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");
+ fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "rb");
}
if (!fptr)
{
- fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/
+ fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "rb");/*Flawfinder: ignore*/
if (!fptr)
{
mNewLoad = false;
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 3fb70a25ad..07ea2219d6 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -131,7 +131,7 @@ public:
LLSpatialGroup* mGroup = nullptr;
// viewer object this probe is tracking (if any)
- LLPointer mViewerObject; // remove initialisation here, leave it to the pointer class and avoid issues
+ LLPointer mViewerObject;
// what priority should this probe have (higher is higher priority)
// currently only 0 or 1
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 95cfd7304e..80a9e73f96 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1359,6 +1359,7 @@ U32 LLTextureCache::openAndReadEntries(std::vector& entries)
if (bytes_read < sizeof(Entry))
{
LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL;
+ closeHeaderEntriesFile();
return 0;
}
entries.push_back(entry);
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index ee42b5c8fc..32ab1272d0 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -1985,7 +1985,13 @@ bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool mo
}
// Further object detail required beyond this point
- LLPermissions* perms = LLSelectMgr::getInstance()->getHoverNode()->mPermissions;
+ LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode();
+ if (hover_node == nullptr)
+ {
+ LL_WARNS() << "No Hover node" << LL_ENDL;
+ return false;
+ }
+ LLPermissions* perms = hover_node->mPermissions;
if(perms == nullptr)
{
LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index e56ab3fe97..39bdc9c8f6 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -240,6 +240,8 @@ LLTrace::SampleStatHandle FRAMETIME_JITTER_EVENTS("frametimeevents", "Numbe
FRAMETIME_JITTER_EVENTS_LAST_MINUTE("frametimeeventslastmin", "Number of frametime events in the last minute.");
LLTrace::SampleStatHandle NOTRMALIZED_FRAMETIME_JITTER_SESSION("normalizedframetimejitter", "Normalized frametime jitter over the session.");
+LLTrace::SampleStatHandle NFTV("nftv", "Normalized frametime variation.");
+LLTrace::SampleStatHandle NORMALIZED_FRAMTIME_JITTER_PERIOD("normalizedframetimejitterperiod", "Normalized frametime jitter over the last 5 seconds.");
LLTrace::EventStatHandle > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections");
@@ -328,6 +330,8 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
sample(LLStatViewer::FRAMETIME_JITTER_CUMULATIVE, mTotalFrametimeJitter);
sample(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION, mTotalFrametimeJitter / mTotalTime);
+ mLastNoramlizedSessionJitter = mTotalFrametimeJitter / mTotalTime;
+
static LLCachedControl frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f);
if (time_diff - mLastTimeDiff > mLastTimeDiff * frameTimeEventThreshold())
@@ -366,6 +370,27 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)
sample(LLStatViewer::FRAMETIME_JITTER_99TH, ninety_ninth_percentile);
sample(LLStatViewer::FRAMETIME_JITTER_95TH, ninety_fifth_percentile);
+ F64 averageFrameTime = 0;
+ for (const auto& frame_time : mFrameTimes)
+ {
+ averageFrameTime += frame_time.value();
+ }
+ averageFrameTime /= mFrameTimes.size();
+
+ sample(LLStatViewer::NFTV, frame_time_stddev / averageFrameTime);
+ mLastNormalizedFrametimeVariance = frame_time_stddev / averageFrameTime;
+
+ // Add up all of the jitter values.
+ F64 totalJitter = 0;
+ for (const auto& frame_jitter : mFrameTimesJitter)
+ {
+ totalJitter += frame_jitter.value();
+ }
+
+ mLastNormalizedPeriodJitter = totalJitter / mLastFrameTimeSample;
+
+ sample(LLStatViewer::NORMALIZED_FRAMTIME_JITTER_PERIOD, mLastNormalizedPeriodJitter);
+
mFrameTimes.clear();
mFrameTimesJitter.clear();
mLastFrameTimeSample = F64Seconds(0);
@@ -654,6 +679,11 @@ void send_viewer_stats(bool include_preferences)
// send fps only for time app spends in foreground
agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32();
+
+ agent["normalized_session_jitter"] = LLViewerStats::instance().getLastNormalizedSessionJitter();
+ agent["normalized_frametime_variance"] = LLViewerStats::instance().getLastNormalizedFrametimeVariance();
+ agent["normalized_period_jitter"] = LLViewerStats::instance().getLastNormalizedPeriodJitter();
+
agent["version"] = LLVersionInfo::instance().getChannelAndVersion();
std::string language = LLUI::getLanguage();
agent["language"] = language;
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index ce4f8ffb01..1c47b2fdde 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -276,6 +276,10 @@ public:
LLTrace::Recording& getRecording() { return mRecording; }
const LLTrace::Recording& getRecording() const { return mRecording; }
+ F64 getLastNormalizedSessionJitter() const { return mLastNoramlizedSessionJitter; }
+ F64 getLastNormalizedFrametimeVariance() const { return mLastNormalizedFrametimeVariance; }
+ F64 getLastNormalizedPeriodJitter() const { return mLastNormalizedPeriodJitter; }
+
private:
LLTrace::Recording mRecording;
@@ -291,6 +295,11 @@ private:
F64Seconds mTimeSinceLastEventSample;
std::vector mFrameTimes; // used for frame time stats
std::vector mFrameTimesJitter; // used for frame time jitter stats
+
+ F64 mLastNoramlizedSessionJitter; // used for frame time jitter stats
+ F64 mLastNormalizedFrametimeVariance; // Used when submitting jitter stats
+ F64 mLastNormalizedPeriodJitter;
+
};
static const F32 SEND_STATS_PERIOD = 300.0f;
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index a7e336febb..0aa7371a1f 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -1921,11 +1921,11 @@ void LLVOCache::removeGenericExtrasForHandle(U64 handle)
}
// NOTE: when removing the extras, we must also remove the objects so the simulator will send us a full upddate with the valid overrides
- auto* entry = mHandleEntryMap[handle];
- if (entry)
+ handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle);
+ if (iter != mHandleEntryMap.end())
{
- LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << entry->mHandle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL;
- removeEntry(entry);
+ LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << handle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL;
+ removeEntry(iter->second);
}
else
{
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index 5b98962a0f..bf1b71825a 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -52,6 +52,7 @@
#include "llcachename.h"
#include "llimview.h" // for LLIMMgr
#include "llworld.h"
+#include "llviewerregion.h"
#include "llparcel.h"
#include "llviewerparcelmgr.h"
#include "llfirstuse.h"
@@ -2004,6 +2005,33 @@ bool LLWebRTCVoiceClient::sessionState::processConnectionStates()
return !mWebRTCConnections.empty();
}
+// Helper function to check if a region supports WebRTC voice
+bool LLWebRTCVoiceClient::estateSessionState::isRegionWebRTCEnabled(const LLUUID& regionID)
+{
+ LLViewerRegion* region = LLWorld::getInstance()->getRegionFromID(regionID);
+ if (!region)
+ {
+ LL_WARNS("Voice") << "Could not find region " << regionID
+ << " for voice server type validation" << LL_ENDL;
+ return false;
+ }
+
+ LLSD simulatorFeatures;
+ region->getSimulatorFeatures(simulatorFeatures);
+
+ bool isWebRTCEnabled = simulatorFeatures.has("VoiceServerType") &&
+ simulatorFeatures["VoiceServerType"].asString() == "webrtc";
+
+ if (!isWebRTCEnabled)
+ {
+ LL_DEBUGS("Voice") << "Region " << regionID << " VoiceServerType is not 'webrtc' (got: "
+ << (simulatorFeatures.has("VoiceServerType") ? simulatorFeatures["VoiceServerType"].asString() : "none") << ")"
+ << LL_ENDL;
+ }
+
+ return isWebRTCEnabled;
+}
+
// processing of spatial voice connection states requires special handling.
// as neighboring regions need to be started up or shut down depending
// on our location.
@@ -2028,6 +2056,13 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates()
// shut down connections to neighbors that are too far away.
spatialConnection.get()->shutDown();
}
+ else if (!isRegionWebRTCEnabled(regionID))
+ {
+ // shut down connections to neighbors that no longer support WebRTC voice.
+ LL_DEBUGS("Voice") << "Shutting down connection to neighbor region " << regionID
+ << " - no longer supports WebRTC voice" << LL_ENDL;
+ spatialConnection.get()->shutDown();
+ }
if (!spatialConnection.get()->isShuttingDown())
{
neighbor_ids.erase(regionID);
@@ -2037,11 +2072,20 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates()
// add new connections for new neighbors
for (auto &neighbor : neighbor_ids)
{
- connectionPtr_t connection(new LLVoiceWebRTCSpatialConnection(neighbor, INVALID_PARCEL_ID, mChannelID));
+ // Only connect if the region supports WebRTC voice server type
+ if (isRegionWebRTCEnabled(neighbor))
+ {
+ connectionPtr_t connection(new LLVoiceWebRTCSpatialConnection(neighbor, INVALID_PARCEL_ID, mChannelID));
- mWebRTCConnections.push_back(connection);
- connection->setMuteMic(mMuted);
- connection->setSpeakerVolume(mSpeakerVolume);
+ mWebRTCConnections.push_back(connection);
+ connection->setMuteMic(mMuted); // mute will be set for primary connection when that connection comes up
+ connection->setSpeakerVolume(mSpeakerVolume);
+ }
+ else
+ {
+ LL_DEBUGS("Voice") << "Skipping neighbor region " << neighbor
+ << " - does not support WebRTC voice" << LL_ENDL;
+ }
}
}
return LLWebRTCVoiceClient::sessionState::processConnectionStates();
@@ -2391,6 +2435,7 @@ void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterfac
}
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
mWebRTCAudioInterface = audio_interface;
+ mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
});
}
@@ -2752,7 +2797,12 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
}
// update the peer connection with the various characteristics of
// this connection.
- mWebRTCAudioInterface->setMute(mMuted);
+ // For spatial this connection will come up as muted, but will be set to the appropriate
+ // value later on when we determine the regions we connect to.
+ if (!isSpatial())
+ {
+ mWebRTCAudioInterface->setMute(mMuted);
+ }
mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL);
@@ -2797,6 +2847,10 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
if (primary != mPrimary)
{
mPrimary = primary;
+ if (mWebRTCAudioInterface)
+ {
+ mWebRTCAudioInterface->setMute(mMuted || !mPrimary);
+ }
sendJoin();
}
}
@@ -3099,10 +3153,7 @@ LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID ®
LLVoiceWebRTCConnection(regionID, channelID),
mParcelLocalID(parcelLocalID)
{
- if (gAgent.getRegion())
- {
- mPrimary = (regionID == gAgent.getRegion()->getRegionID());
- }
+ mPrimary = false; // will be set to primary after connection established
}
LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection()
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index ff82d2739d..71347f206a 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -351,6 +351,9 @@ public:
bool isSpatial() override { return true; }
bool isEstate() override { return true; }
bool isCallbackPossible() override { return false; }
+
+ private:
+ bool isRegionWebRTCEnabled(const LLUUID& regionID);
};
class parcelSessionState : public sessionState
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 83d526a139..e448e8b932 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -518,6 +518,9 @@ Um Medien nur auf einer Fläche einzufügen, wählen Sie „Oberfläche auswähl
Es kostet L$[COST], um diesen Gegenstand hochzuladen.
+
+ Textur konnte aus folgendem Grund nicht kodiert werden: [REASON]
+
Es kostet L$[COST], um eine Textur in Ihrem Inventar zu speichern. Sie können entweder L$ kaufen oder das Foto auf Ihrem Computer speichern.
diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml
index 7858f98752..91941d4420 100644
--- a/indra/newview/skins/default/xui/en/floater_stats.xml
+++ b/indra/newview/skins/default/xui/en/floater_stats.xml
@@ -59,6 +59,14 @@
label="normalized sess. jitter"
decimal_digits="4"
stat="normalizedframetimejitter"/>
+
+
fail
+
+ Failed to encode image, reason: [REASON]
+ fail
+
+