Merge branch 'release/2025.06' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/llxml/llcontrol.cpp
#	indra/newview/llfloaterpreference.cpp
#	indra/newview/lllogchat.cpp
#	indra/newview/llreflectionmap.h
master
Ansariel 2025-08-13 20:52:47 +02:00
commit 478a51f8e3
26 changed files with 197 additions and 31 deletions

View File

@ -558,6 +558,12 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL; 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); setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);
U8 magic[14]; U8 magic[14];

View File

@ -329,6 +329,12 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_
{ {
llassert_always(raw_image); llassert_always(raw_image);
if (raw_image->isBufferInvalid())
{
setLastError("Invalid input, no buffer");
return false;
}
S32 ncomponents = raw_image->getComponents(); S32 ncomponents = raw_image->getComponents();
EFileFormat format; EFileFormat format;
switch (ncomponents) switch (ncomponents)

View File

@ -492,6 +492,12 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
resetLastError(); resetLastError();
if (raw_image->isBufferInvalid())
{
setLastError("Invalid input, no buffer");
return false;
}
LLImageDataSharedLock lockIn(raw_image); LLImageDataSharedLock lockIn(raw_image);
LLImageDataLock lockOut(this); LLImageDataLock lockOut(this);

View File

@ -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) 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); JPEG2KEncode encode(comment_text, reversible);
bool encoded = encode.encode(raw_image, base); bool encoded = encode.encode(raw_image, base);
if (!encoded) if (!encoded)

View File

@ -687,6 +687,12 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
bool vflip = true; bool vflip = true;
bool hflip = false; bool hflip = false;
if (raw_image.isBufferInvalid())
{
base.setLastError("Invalid input, no buffer");
return false;
}
try try
{ {
// Set up input image files // Set up input image files

View File

@ -904,12 +904,12 @@ void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable)
// set_enabled shouldn't be done on the worker thread. // set_enabled shouldn't be done on the worker thread.
if (mPeerConnection) if (mPeerConnection)
{ {
mPeerConnection->SetAudioRecording(enable);
auto senders = mPeerConnection->GetSenders(); auto senders = mPeerConnection->GetSenders();
for (auto &sender : senders) for (auto &sender : senders)
{ {
sender->track()->set_enabled(enable); sender->track()->set_enabled(enable);
} }
mPeerConnection->SetAudioRecording(enable);
} }
} }
@ -964,6 +964,9 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
{ {
if (mPeerConnection) if (mPeerConnection)
{ {
// SetAudioRecording must be called before enabling/disabling tracks.
mPeerConnection->SetAudioRecording(enable);
auto senders = mPeerConnection->GetSenders(); auto senders = mPeerConnection->GetSenders();
RTC_LOG(LS_INFO) << __FUNCTION__ << (mMute ? "disabling" : "enabling") << " streams count " << senders.size(); 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); track->set_enabled(enable);
} }
} }
mPeerConnection->SetAudioRecording(enable);
} }
}); });
} }

View File

@ -1010,7 +1010,7 @@ void LLWindowWin32::close()
// Restore gamma to the system values. // Restore gamma to the system values.
restoreGamma(); restoreGamma();
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; LL_INFOS("Window") << "Destroying Window Thread" << LL_ENDL;
if (sWindowHandleForMessageBox == mWindowHandle) if (sWindowHandleForMessageBox == mWindowHandle)
{ {
@ -5055,7 +5055,7 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{ {
if (mQueue->isClosed()) 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; return false;
} }
@ -5064,6 +5064,11 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{ {
ShowWindow(mWindowHandleThrd, SW_HIDE); ShowWindow(mWindowHandleThrd, SW_HIDE);
} }
else
{
LL_WARNS("Window") << "Tried to hide window, but Win32 window handle is NULL." << LL_ENDL;
return false;
}
mGLReady = false; mGLReady = false;

View File

@ -165,7 +165,10 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
{ {
if ((persist != PERSIST_NO) && mComment.empty()) 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 //Push back versus setValue'ing here, since we don't want to call a signal yet
mValues.push_back(initial); mValues.push_back(initial);

View File

@ -1 +1 @@
7.2.0 7.2.1

View File

@ -1087,7 +1087,7 @@ protected:
menu->setItemEnabled("Chat History", false); menu->setItemEnabled("Chat History", false);
menu->setItemEnabled("Add Contact Set", false); menu->setItemEnabled("Add Contact Set", false);
menu->setItemEnabled("Invite Group", false); menu->setItemEnabled("Invite Group", false);
menu->setItemEnabled("Zoom In", false); menu->setItemEnabled("Zoom In", true);
menu->setItemEnabled("track", false); menu->setItemEnabled("track", false);
menu->setItemEnabled("Share", false); menu->setItemEnabled("Share", false);
menu->setItemEnabled("Pay", false); menu->setItemEnabled("Pay", false);

View File

@ -989,7 +989,7 @@ protected:
menu->setItemEnabled("Voice Call", false); menu->setItemEnabled("Voice Call", false);
menu->setItemEnabled("Chat History", false); menu->setItemEnabled("Chat History", false);
menu->setItemEnabled("Invite Group", false); menu->setItemEnabled("Invite Group", false);
menu->setItemEnabled("Zoom In", false); menu->setItemEnabled("Zoom In", true);
menu->setItemEnabled("Share", false); menu->setItemEnabled("Share", false);
menu->setItemEnabled("Pay", false); menu->setItemEnabled("Pay", false);
menu->setItemEnabled("Block Unblock", false); menu->setItemEnabled("Block Unblock", false);

View File

@ -437,7 +437,9 @@ void LLFloaterImagePreview::onBtnOK()
} }
else else
{ {
LLNotificationsUtil::add("ErrorEncodingImage"); LLSD args;
args["REASON"] = LLImage::getLastThreadError();
LLNotificationsUtil::add("ErrorEncodingImage", args);
LL_WARNS() << "Error encoding image" << LL_ENDL; LL_WARNS() << "Error encoding image" << LL_ENDL;
} }
} }

View File

@ -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 // Beyond that point, if only the user agent is selected, everything is disabled
if (is_single_select && (single_id == gAgentID)) if (is_single_select && (single_id == gAgentID))
{ {
if ("can_zoom_in" == item)
{
return true;
}
if (is_moderator_option) if (is_moderator_option)
{ {
return enableModerateContextMenuItem(item, true); return enableModerateContextMenuItem(item, true);

View File

@ -766,7 +766,8 @@ bool LLFloaterPreference::postBuild()
// <FS:Ansariel> Prefer FS-specific Discord implementation // <FS:Ansariel> Prefer FS-specific Discord implementation
//#ifndef LL_DISCORD //#ifndef LL_DISCORD
// getChild<LLTabContainer>("privacy_tab_container")->childDisable("privacy_preferences_discord"); // LLPanel* panel = getChild<LLPanel>("privacy_preferences_discord");
// getChild<LLTabContainer>("privacy_tab_container")->removeTabPanel(panel);
//#endif //#endif
// </FS:Ansariel> // </FS:Ansariel>

View File

@ -543,8 +543,8 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m
} }
// If we got here, we managed to stat the file. // If we got here, we managed to stat the file.
// Open the file to read // Open the file to read in binary mode to prevent interpreting other characters as EOF
LLFILE* fptr = LLFile::fopen(log_file_name, "r"); /*Flawfinder: ignore*/ LLFILE* fptr = LLFile::fopen(log_file_name, "rb"); /*Flawfinder: ignore*/
if (!fptr) if (!fptr)
{ // Ok, this is strange but not really tragic in the big picture of things { // 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; 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<LL
} }
bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false;
LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "rb");/*Flawfinder: ignore*/
if (!fptr) if (!fptr)
{ {
@ -1352,17 +1352,17 @@ void LLLoadHistoryThread::loadHistory(const std::string& file_name, std::list<LL
old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size());
} }
// </FS:Ansariel> // </FS:Ansariel>
fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "rb");
if (fptr) if (fptr)
{ {
fclose(fptr); fclose(fptr);
LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); 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) if (!fptr)
{ {
fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "rb");/*Flawfinder: ignore*/
if (!fptr) if (!fptr)
{ {
mNewLoad = false; mNewLoad = false;

View File

@ -131,7 +131,7 @@ public:
LLSpatialGroup* mGroup = nullptr; LLSpatialGroup* mGroup = nullptr;
// viewer object this probe is tracking (if any) // viewer object this probe is tracking (if any)
LLPointer<LLViewerObject> mViewerObject; // <FS:Beq/> remove initialisation here, leave it to the pointer class and avoid issues LLPointer<LLViewerObject> mViewerObject;
// what priority should this probe have (higher is higher priority) // what priority should this probe have (higher is higher priority)
// currently only 0 or 1 // currently only 0 or 1

View File

@ -1359,6 +1359,7 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
if (bytes_read < sizeof(Entry)) if (bytes_read < sizeof(Entry))
{ {
LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL; LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL;
closeHeaderEntriesFile();
return 0; return 0;
} }
entries.push_back(entry); entries.push_back(entry);

View File

@ -1985,7 +1985,13 @@ bool LLToolPie::shouldAllowFirstMediaInteraction(const LLPickInfo& pick, bool mo
} }
// Further object detail required beyond this point // 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) if(perms == nullptr)
{ {
LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL; LL_WARNS() << "LLSelectMgr::getInstance()->getHoverNode()->mPermissions is NULL" << LL_ENDL;

View File

@ -240,6 +240,8 @@ LLTrace::SampleStatHandle<U32> FRAMETIME_JITTER_EVENTS("frametimeevents", "Numbe
FRAMETIME_JITTER_EVENTS_LAST_MINUTE("frametimeeventslastmin", "Number of frametime events in the last minute."); FRAMETIME_JITTER_EVENTS_LAST_MINUTE("frametimeeventslastmin", "Number of frametime events in the last minute.");
LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION("normalizedframetimejitter", "Normalized frametime jitter over the session."); LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION("normalizedframetimejitter", "Normalized frametime jitter over the session.");
LLTrace::SampleStatHandle<F64> NFTV("nftv", "Normalized frametime variation.");
LLTrace::SampleStatHandle<F64> NORMALIZED_FRAMTIME_JITTER_PERIOD("normalizedframetimejitterperiod", "Normalized frametime jitter over the last 5 seconds.");
LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > 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::FRAMETIME_JITTER_CUMULATIVE, mTotalFrametimeJitter);
sample(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION, mTotalFrametimeJitter / mTotalTime); sample(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION, mTotalFrametimeJitter / mTotalTime);
mLastNoramlizedSessionJitter = mTotalFrametimeJitter / mTotalTime;
static LLCachedControl<F32> frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f); static LLCachedControl<F32> frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f);
if (time_diff - mLastTimeDiff > mLastTimeDiff * frameTimeEventThreshold()) 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_99TH, ninety_ninth_percentile);
sample(LLStatViewer::FRAMETIME_JITTER_95TH, ninety_fifth_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(); mFrameTimes.clear();
mFrameTimesJitter.clear(); mFrameTimesJitter.clear();
mLastFrameTimeSample = F64Seconds(0); mLastFrameTimeSample = F64Seconds(0);
@ -654,6 +679,11 @@ void send_viewer_stats(bool include_preferences)
// send fps only for time app spends in foreground // send fps only for time app spends in foreground
agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); 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(); agent["version"] = LLVersionInfo::instance().getChannelAndVersion();
std::string language = LLUI::getLanguage(); std::string language = LLUI::getLanguage();
agent["language"] = language; agent["language"] = language;

View File

@ -276,6 +276,10 @@ public:
LLTrace::Recording& getRecording() { return mRecording; } LLTrace::Recording& getRecording() { return mRecording; }
const LLTrace::Recording& getRecording() const { 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: private:
LLTrace::Recording mRecording; LLTrace::Recording mRecording;
@ -291,6 +295,11 @@ private:
F64Seconds mTimeSinceLastEventSample; F64Seconds mTimeSinceLastEventSample;
std::vector<F64Seconds> mFrameTimes; // used for frame time stats std::vector<F64Seconds> mFrameTimes; // used for frame time stats
std::vector<F64Seconds> mFrameTimesJitter; // used for frame time jitter stats std::vector<F64Seconds> 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; static const F32 SEND_STATS_PERIOD = 300.0f;

View File

@ -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 // 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]; handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle);
if (entry) if (iter != mHandleEntryMap.end())
{ {
LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << entry->mHandle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL; LL_WARNS("GLTF", "VOCache") << "Removing generic extras for handle " << handle << "Filename: " << getObjectCacheExtrasFilename(handle) << LL_ENDL;
removeEntry(entry); removeEntry(iter->second);
} }
else else
{ {

View File

@ -52,6 +52,7 @@
#include "llcachename.h" #include "llcachename.h"
#include "llimview.h" // for LLIMMgr #include "llimview.h" // for LLIMMgr
#include "llworld.h" #include "llworld.h"
#include "llviewerregion.h"
#include "llparcel.h" #include "llparcel.h"
#include "llviewerparcelmgr.h" #include "llviewerparcelmgr.h"
#include "llfirstuse.h" #include "llfirstuse.h"
@ -2004,6 +2005,33 @@ bool LLWebRTCVoiceClient::sessionState::processConnectionStates()
return !mWebRTCConnections.empty(); 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. // processing of spatial voice connection states requires special handling.
// as neighboring regions need to be started up or shut down depending // as neighboring regions need to be started up or shut down depending
// on our location. // on our location.
@ -2028,6 +2056,13 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates()
// shut down connections to neighbors that are too far away. // shut down connections to neighbors that are too far away.
spatialConnection.get()->shutDown(); 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()) if (!spatialConnection.get()->isShuttingDown())
{ {
neighbor_ids.erase(regionID); neighbor_ids.erase(regionID);
@ -2037,11 +2072,20 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates()
// add new connections for new neighbors // add new connections for new neighbors
for (auto &neighbor : neighbor_ids) 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); mWebRTCConnections.push_back(connection);
connection->setMuteMic(mMuted); connection->setMuteMic(mMuted); // mute will be set for primary connection when that connection comes up
connection->setSpeakerVolume(mSpeakerVolume); connection->setSpeakerVolume(mSpeakerVolume);
}
else
{
LL_DEBUGS("Voice") << "Skipping neighbor region " << neighbor
<< " - does not support WebRTC voice" << LL_ENDL;
}
} }
} }
return LLWebRTCVoiceClient::sessionState::processConnectionStates(); return LLWebRTCVoiceClient::sessionState::processConnectionStates();
@ -2391,6 +2435,7 @@ void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterfac
} }
LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL; LL_DEBUGS("Voice") << "On AudioEstablished." << LL_ENDL;
mWebRTCAudioInterface = audio_interface; mWebRTCAudioInterface = audio_interface;
mWebRTCAudioInterface->setMute(true); // mute will be set appropriately later when we finish setting up.
setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED); setVoiceConnectionState(VOICE_STATE_SESSION_ESTABLISHED);
}); });
} }
@ -2752,7 +2797,12 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
} }
// update the peer connection with the various characteristics of // update the peer connection with the various characteristics of
// this connection. // 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); mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID); LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL); setVoiceConnectionState(VOICE_STATE_WAIT_FOR_DATA_CHANNEL);
@ -2797,6 +2847,10 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
if (primary != mPrimary) if (primary != mPrimary)
{ {
mPrimary = primary; mPrimary = primary;
if (mWebRTCAudioInterface)
{
mWebRTCAudioInterface->setMute(mMuted || !mPrimary);
}
sendJoin(); sendJoin();
} }
} }
@ -3099,10 +3153,7 @@ LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID &reg
LLVoiceWebRTCConnection(regionID, channelID), LLVoiceWebRTCConnection(regionID, channelID),
mParcelLocalID(parcelLocalID) mParcelLocalID(parcelLocalID)
{ {
if (gAgent.getRegion()) mPrimary = false; // will be set to primary after connection established
{
mPrimary = (regionID == gAgent.getRegion()->getRegionID());
}
} }
LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection()

View File

@ -351,6 +351,9 @@ public:
bool isSpatial() override { return true; } bool isSpatial() override { return true; }
bool isEstate() override { return true; } bool isEstate() override { return true; }
bool isCallbackPossible() override { return false; } bool isCallbackPossible() override { return false; }
private:
bool isRegionWebRTCEnabled(const LLUUID& regionID);
}; };
class parcelSessionState : public sessionState class parcelSessionState : public sessionState

View File

@ -518,6 +518,9 @@ Um Medien nur auf einer Fläche einzufügen, wählen Sie „Oberfläche auswähl
<notification name="ErrorCannotAffordUpload"> <notification name="ErrorCannotAffordUpload">
Es kostet L$[COST], um diesen Gegenstand hochzuladen. Es kostet L$[COST], um diesen Gegenstand hochzuladen.
</notification> </notification>
<notification name="ErrorEncodingImage">
Textur konnte aus folgendem Grund nicht kodiert werden: [REASON]
</notification>
<notification name="ErrorTextureCannotAfford"> <notification name="ErrorTextureCannotAfford">
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. 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.
</notification> </notification>

View File

@ -59,6 +59,14 @@
label="normalized sess. jitter" label="normalized sess. jitter"
decimal_digits="4" decimal_digits="4"
stat="normalizedframetimejitter"/> stat="normalizedframetimejitter"/>
<stat_bar name="normalized_period_jitter"
label="normalized period jitter"
decimal_digits="4"
stat="normalizedframetimejitterperiod"/>
<stat_bar name="normalized_frametime_variation"
label="normalized frametime variation"
decimal_digits="4"
stat="nftv"/>
<stat_bar name="frame_events_per_minute" <stat_bar name="frame_events_per_minute"
label="frame events/minute" label="frame events/minute"
decimal_digits="2" decimal_digits="2"

View File

@ -1320,6 +1320,14 @@ Error encoding snapshot.
<tag>fail</tag> <tag>fail</tag>
</notification> </notification>
<notification
icon="alertmodal.tga"
name="ErrorEncodingImage"
type="alertmodal">
Failed to encode image, reason: [REASON]
<tag>fail</tag>
</notification>
<notification <notification
icon="alertmodal.tga" icon="alertmodal.tga"
name="ErrorTextureCannotAfford" name="ErrorTextureCannotAfford"