diff options
author | Erik Kundiman <erik@megapahit.org> | 2024-08-19 19:59:03 +0800 |
---|---|---|
committer | Erik Kundiman <erik@megapahit.org> | 2024-08-19 19:59:03 +0800 |
commit | 495f103000137b3288eaa05a4298fd33ceb3c2dc (patch) | |
tree | 19b79a5cb33275a874d24e923a04de7b9657401b /indra | |
parent | b7a79709003b1f7f0451ba577576040fc03e50f9 (diff) | |
parent | 0f3ffb0fad721740f20ed5c7a74f4ceade6d46b6 (diff) |
Merge remote-tracking branch 'secondlife/release/2024.06-atlasaurus' into 2024.06-atlasaurus
Diffstat (limited to 'indra')
66 files changed, 585 insertions, 412 deletions
diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index a297e04143..8e91dac109 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -19,6 +19,7 @@ if (WINDOWS OR DARWIN ) endif() else() set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,>) + set(SYMBOLS_STAGING_DIR ${CMAKE_BINARY_DIR}/symbols/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,>/${VIEWER_CHANNEL}) endif() if( DARWIN ) diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index bf5a6df556..cbb703e9e7 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -198,7 +198,7 @@ namespace LLError }; /** - * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership + * @NOTE: addRecorder() and removeRecorder() uses the std::shared_ptr to allow for shared ownership * while still ensuring that the allocated memory is eventually freed */ LL_COMMON_API void addRecorder(RecorderPtr); diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index be3e585ef8..375cb050cc 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -159,7 +159,8 @@ AccumulatorBufferGroup* ThreadRecorder::activate( AccumulatorBufferGroup* record ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording ) { #if LL_TRACE_ENABLED - if (mActiveRecordings.empty()) return mActiveRecordings.end(); + if (mActiveRecordings.empty()) + return mActiveRecordings.end(); mActiveRecordings.back()->mPartialRecording.sync(); BlockTimer::updateTimes(); @@ -202,7 +203,7 @@ ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( #endif } -void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording ) +void ThreadRecorder::deactivate(AccumulatorBufferGroup* recording) { #if LL_TRACE_ENABLED active_recording_list_t::iterator recording_it = bringUpToDate(recording); @@ -228,9 +229,10 @@ void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording ) #endif } -ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) +ThreadRecorder::ActiveRecording::ActiveRecording(AccumulatorBufferGroup* target) : mTargetRecording(target) -{} +{ +} void ThreadRecorder::ActiveRecording::movePartialToTarget() { @@ -243,30 +245,30 @@ void ThreadRecorder::ActiveRecording::movePartialToTarget() // called by child thread -void ThreadRecorder::addChildRecorder( class ThreadRecorder* child ) +void ThreadRecorder::addChildRecorder(ThreadRecorder* child) { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.push_back(child); - } + LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.push_back(child); #endif } // called by child thread -void ThreadRecorder::removeChildRecorder( class ThreadRecorder* child ) +void ThreadRecorder::removeChildRecorder(ThreadRecorder* child) { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.remove(child); - } + LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.remove(child); #endif } void ThreadRecorder::pushToParent() { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mSharedRecordingMutex); - LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); + if (ThreadRecorder* recorder = LLTrace::get_thread_recorder()) + { + LLMutexLock lock(&mSharedRecordingMutex); + recorder->bringUpToDate(&mThreadRecordingBuffers); mSharedRecordingBuffers.append(mThreadRecordingBuffers); mThreadRecordingBuffers.reset(); } @@ -278,15 +280,14 @@ void ThreadRecorder::pullFromChildren() { #if LL_TRACE_ENABLED LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (mActiveRecordings.empty()) return; - - { LLMutexLock lock(&mChildListMutex); - + if (!mActiveRecordings.empty()) + { + LLMutexLock lock(&mChildListMutex); AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; target_recording_buffers.sync(); for (LLTrace::ThreadRecorder* rec : mChildThreadRecorders) - { LLMutexLock lock(&(rec->mSharedRecordingMutex)); - + { + LLMutexLock lock(&(rec->mSharedRecordingMutex)); target_recording_buffers.merge(rec->mSharedRecordingBuffers); rec->mSharedRecordingBuffers.reset(); } @@ -294,13 +295,11 @@ void ThreadRecorder::pullFromChildren() #endif } - -void set_master_thread_recorder( ThreadRecorder* recorder ) +void set_master_thread_recorder(ThreadRecorder* recorder) { sMasterThreadRecorder = recorder; } - ThreadRecorder* get_master_thread_recorder() { return sMasterThreadRecorder; diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp index 2ff1cc74c6..99f917d94b 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -28,7 +28,6 @@ #include "llsettingsdaycycle.h" #include "llerror.h" #include <algorithm> -#include <boost/make_shared.hpp> #include "lltrace.h" #include "llfasttimer.h" #include "v3colorutil.h" diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp index 84542e2cb4..a6a25b0953 100644 --- a/indra/llinventory/llsettingswater.cpp +++ b/indra/llinventory/llsettingswater.cpp @@ -27,7 +27,6 @@ #include "llsettingswater.h" #include <algorithm> -#include <boost/make_shared.hpp> #include "lltrace.h" #include "llfasttimer.h" #include "v3colorutil.h" diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 63ac46722a..64f660d0ce 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -53,7 +53,6 @@ const U32 PENDING_TIMEOUT_SECS = 5 * 60; // Globals LLCacheName* gCacheName = NULL; -std::map<std::string, std::string> LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -215,7 +214,7 @@ public: Impl(LLMessageSystem* msg); ~Impl(); - bool getName(const LLUUID& id, std::string& first, std::string& last); + bool getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names); boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); void addPending(const LLUUID& id, const LLHost& host); @@ -247,9 +246,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { - sCacheName["waiting"] = "(Loading...)"; - sCacheName["nobody"] = "(nobody)"; - sCacheName["none"] = "(none)"; + mCacheName["waiting"] = "(Loading...)"; + mCacheName["nobody"] = "(nobody)"; + mCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -274,7 +273,7 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { - for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + std::for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); mCache.clear(); for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); mReplyQueue.clear(); @@ -402,11 +401,11 @@ void LLCacheName::exportFile(std::ostream& ostr) } -bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last) +bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last, std::map<std::string, std::string>& default_names) { if(id.isNull()) { - first = sCacheName["nobody"]; + first = default_names["nobody"]; last.clear(); return true; } @@ -420,7 +419,7 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin } else { - first = sCacheName["waiting"]; + first = default_names["waiting"]; last.clear(); if (!isRequestPending(id)) { @@ -434,8 +433,8 @@ bool LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::strin // static void LLCacheName::localizeCacheName(std::string key, std::string value) { - if (key!="" && value!= "" ) - sCacheName[key]=value; + if (!key.empty() && !value.empty()) + mCacheName[key]=value; else LL_WARNS()<< " Error localizing cache key " << key << " To "<< value<<LL_ENDL; } @@ -443,7 +442,7 @@ void LLCacheName::localizeCacheName(std::string key, std::string value) bool LLCacheName::getFullName(const LLUUID& id, std::string& fullname) { std::string first_name, last_name; - bool res = impl.getName(id, first_name, last_name); + bool res = impl.getName(id, first_name, last_name, mCacheName); fullname = buildFullName(first_name, last_name); return res; } @@ -454,7 +453,7 @@ bool LLCacheName::getGroupName(const LLUUID& id, std::string& group) { if(id.isNull()) { - group = sCacheName["none"]; + group = mCacheName["none"]; return true; } @@ -475,7 +474,7 @@ bool LLCacheName::getGroupName(const LLUUID& id, std::string& group) } else { - group = sCacheName["waiting"]; + group = mCacheName["waiting"]; if (!impl.isRequestPending(id)) { impl.mAskGroupQueue.insert(id); @@ -614,7 +613,7 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, co { LLCacheNameSignal signal; signal.connect(callback); - signal(id, sCacheName["nobody"], is_group); + signal(id, mCacheName["nobody"], is_group); return res; } @@ -754,14 +753,14 @@ void LLCacheName::dumpStats() void LLCacheName::clear() { - for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer()); + std::for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer()); impl.mCache.clear(); } //static std::string LLCacheName::getDefaultName() { - return sCacheName["waiting"]; + return mCacheName["waiting"]; } //static diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 1df713c7c7..609387b6de 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -127,15 +127,16 @@ public: void dumpStats(); // Dumps the sizes of the cache and associated queues. void clear(); // Deletes all entries from the cache - static std::string getDefaultName(); + std::string getDefaultName(); // Returns "Resident", the default last name for SLID-based accounts // that have no last name. static std::string getDefaultLastName(); - static void localizeCacheName(std::string key, std::string value); - static std::map<std::string, std::string> sCacheName; + void localizeCacheName(std::string key, std::string value); + private: + std::map<std::string, std::string> mCacheName; class Impl; Impl& impl; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index e6ecf3c283..f29f9286c9 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1926,6 +1926,14 @@ void LLFloater::onClickClose( LLFloater* self ) self->onClickCloseBtn(); } +// static +void LLFloater::onClickClose(LLFloater* self, bool app_quitting) +{ + if (!self) + return; + self->onClickCloseBtn(app_quitting); +} + void LLFloater::onClickCloseBtn(bool app_quitting) { closeFloater(false); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 3d75c42f60..9be2240f6f 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -363,6 +363,7 @@ public: // } static void onClickClose(LLFloater* floater); + static void onClickClose(LLFloater* floater, bool app_quitting); static void onClickMinimize(LLFloater* floater); static void onClickTearOff(LLFloater* floater); static void onClickDock(LLFloater* floater); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 74a9641836..1d9564d107 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1479,7 +1479,11 @@ const std::string LLScrollListCtrl::getSelectedItemLabel(S32 column) const item = getFirstSelected(); if (item) { - return item->getColumn(column)->getValue().asString(); + auto col = item->getColumn(column); + if(col) + { + return col->getValue().asString(); + } } return LLStringUtil::null; diff --git a/indra/llwebrtc/CMakeLists.txt b/indra/llwebrtc/CMakeLists.txt index 48ce551516..d6217ff3a4 100644 --- a/indra/llwebrtc/CMakeLists.txt +++ b/indra/llwebrtc/CMakeLists.txt @@ -33,7 +33,11 @@ set_target_properties(llwebrtc PROPERTIES PUBLIC_HEADER llwebrtc.h) endif () if (WINDOWS) - target_link_libraries(llwebrtc PRIVATE ll::webrtc + set_target_properties(llwebrtc + PROPERTIES + LINK_FLAGS "/debug /LARGEADDRESSAWARE" + ) + target_link_libraries(llwebrtc PRIVATE ll::webrtc secur32 winmm dmoguids @@ -41,8 +45,15 @@ if (WINDOWS) msdmo strmiids iphlpapi) + if (USE_BUGSPLAT) + set_target_properties(llwebrtc PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}") + endif (USE_BUGSPLAT) elseif (DARWIN) target_link_libraries(llwebrtc PRIVATE ll::webrtc) + if (USE_BUGSPLAT) + set_target_properties(llwebrtc PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" + XCODE_ATTRIBUTE_DWARF_DSYM_FOLDER_PATH "${SYMBOLS_STAGING_DIR}/dSYMs") + endif (USE_BUGSPLAT) elseif (LINUX) target_link_libraries(llwebrtc PRIVATE ll::webrtc) endif (WINDOWS) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 97d501ca2e..c3e46cc615 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2154,8 +2154,6 @@ if (DARWIN) set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,>/${product}.app") set(VIEWER_APP_EXE "${VIEWER_APP_BUNDLE}/Contents/MacOS/${product}") - set(VIEWER_APP_DSYM "${VIEWER_APP_EXE}.dSYM") - set(VIEWER_APP_XCARCHIVE "${VIEWER_APP_BUNDLE}/../${product}.xcarchive.zip") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" @@ -2255,73 +2253,51 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -# Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE) if (USE_BUGSPLAT) # BugSplat symbol-file generation if (WINDOWS) - # Just pack up a tarball containing only the .pdb file for the - # executable. Because we intend to use cygwin tar, we must render - # VIEWER_SYMBOL_FILE in cygwin path syntax. - execute_process(COMMAND "cygpath" "-u" "${VIEWER_SYMBOL_FILE}" - OUTPUT_VARIABLE VIEWER_SYMBOL_FILE_CYGWIN - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND "cygpath" "-u" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" - OUTPUT_VARIABLE PARENT_DIRECTORY_CYGWIN - OUTPUT_STRIP_TRAILING_WHITESPACE) - add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - # Use of 'tar ...J' here assumes VIEWER_SYMBOL_FILE endswith .tar.xz; - # testing a string suffix is painful enough in CMake language that - # we'll continue assuming it until forced to generalize. + set(VIEWER_APP_SYMBOLS_ARCHIVE "${SYMBOLS_STAGING_DIR}.sym.tar.xz") + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}") + + # Just pack up a tarball containing only the .pdb files for the + # executables. + add_custom_command(OUTPUT "${VIEWER_APP_SYMBOLS_ARCHIVE}" COMMAND "tar" ARGS "cJf" - "${VIEWER_SYMBOL_FILE_CYGWIN}" - "-C" - "${PARENT_DIRECTORY_CYGWIN}" - "secondlife-bin.pdb" - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-bin.pdb" - COMMENT "Packing viewer PDB into ${VIEWER_SYMBOL_FILE_CYGWIN}" + "${VIEWER_CHANNEL}.sym.tar.xz" + "${VIEWER_CHANNEL}" + DEPENDS "${VIEWER_BINARY_NAME}" llwebrtc + WORKING_DIRECTORY "${SYMBOLS_STAGING_DIR}/.." + COMMENT "Packing viewer PDBs into ${VIEWER_APP_SYMBOLS_ARCHIVE}" ) - add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME}) - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) + add_custom_target(generate_symbols DEPENDS "${VIEWER_APP_SYMBOLS_ARCHIVE}") + add_dependencies(generate_symbols ${VIEWER_BINARY_NAME} llwebrtc) + endif (WINDOWS) if (DARWIN) - # Have to run dsymutil first, then pack up the resulting .dSYM directory - add_custom_command(OUTPUT "${VIEWER_APP_DSYM}" - COMMAND "dsymutil" - ARGS - ${VIEWER_APP_EXE} - COMMENT "Generating ${VIEWER_APP_DSYM}" - ) - add_custom_target(dsym_generate DEPENDS "${VIEWER_APP_DSYM}") - add_dependencies(dsym_generate ${VIEWER_BINARY_NAME}) + set(VIEWER_APP_XCARCHIVE "${SYMBOLS_STAGING_DIR}.xcarchive.zip") + + # we only need an xcarchive with dSYMs (including the application) + set_target_properties(${VIEWER_BINARY_NAME} + PROPERTIES + XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" + XCODE_ATTRIBUTE_DWARF_DSYM_FOLDER_PATH "${SYMBOLS_STAGING_DIR}/dSYMs") + add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}" - COMMAND "zip" - ARGS - "-r" - "${VIEWER_APP_XCARCHIVE}" - "." - WORKING_DIRECTORY "${VIEWER_APP_DSYM}/.." - DEPENDS "${VIEWER_APP_DSYM}" - COMMENT "Generating xcarchive.zip for upload to BugSplat" - ) - add_custom_target(dsym_xcarchive DEPENDS "${VIEWER_APP_XCARCHIVE}") - add_dependencies(dsym_xcarchive dsym_generate) - # Have to create a stamp file, and depend on it, to force CMake to run - # the cleanup step. - add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - COMMAND rm -rf "${VIEWER_APP_DSYM}" - COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" - DEPENDS "${VIEWER_APP_XCARCHIVE}" - COMMENT "Cleaning up dSYM" - ) + COMMAND "zip" + ARGS + "-r" + "${VIEWER_APP_XCARCHIVE}" + "${VIEWER_CHANNEL}" + WORKING_DIRECTORY "${SYMBOLS_STAGING_DIR}/.." + DEPENDS "${VIEWER_BINARY_NAME}" llwebrtc + COMMENT "Generating ${VIEWER_APP_XCARCHIVE} for upload to BugSplat" + ) add_custom_target(generate_symbols DEPENDS - "${VIEWER_APP_DSYM}" "${VIEWER_APP_XCARCHIVE}" - "${CMAKE_CURRENT_BINARY_DIR}/dsym.stamp" ) - add_dependencies(generate_symbols dsym_xcarchive) endif (DARWIN) if (LINUX) # TBD diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 9dd23a5319..6411be3d4f 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2133,11 +2133,11 @@ void LLAppearanceMgr::filterWearableItems( items.clear(); for (S32 i=0; i<LLWearableType::WT_COUNT; i++) { - auto size = items_by_type[i].size(); + S32 size = (S32)items_by_type[i].size(); if (size <= 0) continue; - auto start_index = llmax(0,size-max_per_type); - for (size_t j = start_index; j<size; j++) + S32 start_index = llmax(0,size-max_per_type); + for (S32 j = start_index; j<size; j++) { items.push_back(items_by_type[i][j]); } diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index eac1ee2a3c..ec55768673 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -98,10 +98,7 @@ LLConversationViewSession::~LLConversationViewSession() if (mVoiceClientObserver) { - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver); - } + LLVoiceClient::removeObserver(mVoiceClientObserver); delete mVoiceClientObserver; } @@ -259,16 +256,15 @@ bool LLConversationViewSession::postBuild() icon->setVisible(true); mSpeakingIndicator->setSpeakerId(gAgentID, LLUUID::null, true); mIsInActiveVoiceChannel = true; - if(LLVoiceClient::instanceExists()) + + if (mVoiceClientObserver) { - if (mVoiceClientObserver) - { - LLVoiceClient::getInstance()->removeObserver(mVoiceClientObserver); - delete mVoiceClientObserver; - } - mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this); - LLVoiceClient::getInstance()->addObserver(mVoiceClientObserver); + LLVoiceClient::removeObserver(mVoiceClientObserver); + delete mVoiceClientObserver; } + mVoiceClientObserver = new LLNearbyVoiceClientStatusObserver(this); + LLVoiceClient::addObserver(mVoiceClientObserver); + break; } default: diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 8884905cf0..79011b2f97 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -54,8 +54,6 @@ #include "llregioninfomodel.h" -#include <boost/make_shared.hpp> - #include "llatmosphere.h" #include "llagent.h" #include "roles_constants.h" diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 471bb6d478..c05a7fef44 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -40,8 +40,6 @@ #include "llcorehttputil.h" #include "lleventfilter.h" -#include "boost/make_shared.hpp" - namespace LLEventPolling { namespace Details diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 367803b78a..806d51a5fd 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -775,7 +775,7 @@ bool LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) } } - if (volume->mDrawable.isNull()) + if (volume->mDrawable.isNull() || volume->mDrawable->isDead()) { return true; // No update to complete } diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 6087e6c0ee..08a54b7369 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -300,7 +300,7 @@ void LLFloaterAvatarPicker::populateNearMe() if (!LLAvatarNameCache::get(av, &av_name)) { element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = LLCacheName::getDefaultName(); + element["columns"][0]["value"] = gCacheName->getDefaultName(); all_loaded = false; } else diff --git a/indra/newview/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp index bd5839ed17..a42c94f049 100644 --- a/indra/newview/llfloatereditenvironmentbase.cpp +++ b/indra/newview/llfloatereditenvironmentbase.cpp @@ -28,8 +28,6 @@ #include "llfloatereditenvironmentbase.h" -#include <boost/make_shared.hpp> - // libs #include "llnotifications.h" #include "llnotificationsutil.h" diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp index 6829e6b479..e44202312b 100644 --- a/indra/newview/llfloaterfixedenvironment.cpp +++ b/indra/newview/llfloaterfixedenvironment.cpp @@ -28,8 +28,6 @@ #include "llfloaterfixedenvironment.h" -#include <boost/make_shared.hpp> - // libs #include "llbutton.h" #include "llnotifications.h" diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index add389748f..cf66507a66 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -988,11 +988,14 @@ void LLFloaterIMContainer::onAddButtonClicked() { LLView * button = findChild<LLView>("conversations_pane_buttons_expanded")->findChild<LLButton>("add_btn"); LLFloater* root_floater = gFloaterView->getParentFloater(this); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLFloaterIMContainer::onAvatarPicked, this, _1), true, true, true, root_floater->getName(), button); - - if (picker && root_floater) + if (button && root_floater) { - root_floater->addDependentFloater(picker); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLFloaterIMContainer::onAvatarPicked, this, _1), true, true, true, root_floater->getName(), button); + + if (picker) + { + root_floater->addDependentFloater(picker); + } } } @@ -2429,7 +2432,7 @@ void LLFloaterIMContainer::closeHostedFloater() onClickCloseBtn(); } -void LLFloaterIMContainer::closeAllConversations() +void LLFloaterIMContainer::closeAllConversations(bool app_quitting) { std::vector<LLUUID> ids; for (conversations_items_map::iterator it_session = mConversationsItems.begin(); it_session != mConversationsItems.end(); it_session++) @@ -2444,7 +2447,7 @@ void LLFloaterIMContainer::closeAllConversations() for (std::vector<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it) { LLFloaterIMSession *conversationFloater = LLFloaterIMSession::findInstance(*it); - LLFloater::onClickClose(conversationFloater); + LLFloater::onClickClose(conversationFloater, app_quitting); } } @@ -2467,7 +2470,7 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/) { if(app_quitting) { - closeAllConversations(); + closeAllConversations(app_quitting); onClickCloseBtn(app_quitting); } else diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index e11445d779..d1cfd3442c 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -117,7 +117,7 @@ public: void assignResizeLimits(); virtual bool handleKeyHere(KEY key, MASK mask ); /*virtual*/ void closeFloater(bool app_quitting = false); - void closeAllConversations(); + void closeAllConversations(bool app_quitting); void closeSelectedConversations(const uuid_vec_t& ids); /*virtual*/ bool isFrontmost(); diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index 5dd78fe1db..557b3f27c5 100644 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -138,8 +138,14 @@ void LLFloaterIMSession::onTearOffClicked() } // virtual -void LLFloaterIMSession::onClickCloseBtn(bool) +void LLFloaterIMSession::onClickCloseBtn(bool app_qutting) { + if (app_qutting) + { + LLFloaterIMSessionTab::onClickCloseBtn(); + return; + } + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID); if (session != NULL) @@ -287,10 +293,8 @@ void LLFloaterIMSession::sendMsg(const std::string& msg) LLFloaterIMSession::~LLFloaterIMSession() { mVoiceChannelStateChangeConnection.disconnect(); - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + + LLVoiceClient::removeObserver(this); LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this); @@ -366,7 +370,7 @@ bool LLFloaterIMSession::postBuild() childSetAction("voice_call_btn", boost::bind(&LLFloaterIMSession::onCallButtonClicked, this)); - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); //*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla" //see LLFloaterIMPanel for how it is done (IB) @@ -537,6 +541,7 @@ void LLFloaterIMSession::boundVoiceChannel() LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); if(voice_channel) { + mVoiceChannelStateChangeConnection.disconnect(); mVoiceChannelStateChangeConnection = voice_channel->setStateChangedCallback( boost::bind(&LLFloaterIMSession::onVoiceChannelStateChanged, this, _1, _2)); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index a0b56b14f0..a74622faec 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -546,6 +546,12 @@ void LLFloaterIMSessionTab::closeFloater(bool app_quitting) super::closeFloater(app_quitting); } +void LLFloaterIMSessionTab::deleteAllChildren() +{ + super::deleteAllChildren(); + mVoiceButton = NULL; +} + std::string LLFloaterIMSessionTab::appendTime() { std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:" diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 0a8502cfc5..9ca9b8444d 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -82,6 +82,7 @@ public: /*virtual*/ void setVisible(bool visible); /*virtual*/ void setFocus(bool focus); /*virtual*/ void closeFloater(bool app_quitting = false); + /*virtual*/ void deleteAllChildren(); // Handle the left hand participant list widgets void addConversationViewParticipant(LLConversationItem* item, bool update_view = true); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 6d30cb1f95..14ae03d9ce 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -852,8 +852,9 @@ void LLPanelRegionInfo::initCtrl(const std::string& name) template<typename CTRL> void LLPanelRegionInfo::initAndSetCtrl(CTRL*& ctrl, const std::string& name) { - initCtrl(name); ctrl = findChild<CTRL>(name); + if (ctrl) + ctrl->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this)); } void LLPanelRegionInfo::onClickManageTelehub() diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d402f8b74f..75d96cbe26 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3042,13 +3042,16 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload gIMMgr->addSession(correct_session_name, type, session_id, payload["voice_channel_info"]); - std::string url = gAgent.getRegion()->getCapability( + std::string url = gAgent.getRegionCapability( "ChatSessionRequest"); if (voice) { - LLCoros::instance().launch("chatterBoxInvitationCoro", - boost::bind(&chatterBoxInvitationCoro, url, session_id, inv_type, payload["voice_channel_info"])); + if(!url.empty()) + { + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, session_id, inv_type, payload["voice_channel_info"])); + } // send notification message to the corresponding chat if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") @@ -3858,6 +3861,11 @@ bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection dir { voice_channel->setChannelInfo(voice_channel_info); } + else if (voice_channel->getState() < LLVoiceChannel::STATE_READY) + { + // restart if there wa an error or it was hang up + voice_channel->resetChannelInfo(); + } voice_channel->setCallDirection(direction); voice_channel->activate(); return true; @@ -4063,9 +4071,12 @@ public: // Send request for chat history, if enabled. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) { - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); - LLCoros::instance().launch("chatterBoxHistoryCoro", - boost::bind(&chatterBoxHistoryCoro, url, session_id, "", "", 0)); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); + if (!url.empty()) + { + LLCoros::instance().launch("chatterBoxHistoryCoro", + boost::bind(&chatterBoxHistoryCoro, url, session_id, "", "", 0)); + } } } } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index df57504969..d40806ec2e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -961,7 +961,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } - if (obj->getType() != LLAssetType::AT_CATEGORY) + if (obj && obj->getType() != LLAssetType::AT_CATEGORY) { items.push_back(std::string("Paste Separator")); } @@ -6303,7 +6303,7 @@ void LLCallingCardBridge::performAction(LLInventoryModel* model, std::string act if (item && (item->getCreatorUUID() != gAgent.getID()) && (!item->getCreatorUUID().isNull())) { - std::string callingcard_name = LLCacheName::getDefaultName(); + std::string callingcard_name = gCacheName->getDefaultName(); LLAvatarName av_name; if (LLAvatarNameCache::get(item->getCreatorUUID(), &av_name)) { diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index c69f797868..b99dbd9eb7 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -221,9 +221,10 @@ void LLInventoryGallery::setRootFolder(const LLUUID cat_id) for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } @@ -348,7 +349,7 @@ void LLInventoryGallery::initGallery() mScrollPanel->addChild(mGalleryPanel); for (int i = 0; i < n; i++) { - addToGallery(mItemMap[cats[i]]); + addToGallery(getItem(cats[i])); } reArrangeRows(); mGalleryCreated = true; @@ -656,6 +657,16 @@ LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, L return gitem; } +LLInventoryGalleryItem* LLInventoryGallery::getItem(const LLUUID& id) const +{ + auto it = mItemMap.find(id); + if (it != mItemMap.end()) + { + return it->second; + } + return nullptr; +} + void LLInventoryGallery::buildGalleryPanel(int row_count) { LLPanel::Params params; @@ -1006,14 +1017,15 @@ void LLInventoryGallery::updateItemThumbnail(LLUUID item_id) thumbnail_id = getOutfitImageID(item_id); } - if (mItemMap[item_id]) + LLInventoryGalleryItem* item = getItem(item_id); + if (item) { - mItemMap[item_id]->setLoadImmediately(mLoadThumbnailsImmediately); - mItemMap[item_id]->setThumbnail(thumbnail_id); + item->setLoadImmediately(mLoadThumbnailsImmediately); + item->setThumbnail(thumbnail_id); - bool passes_filter = checkAgainstFilters(mItemMap[item_id], mFilterSubString); - if((mItemMap[item_id]->isHidden() && passes_filter) - || (!mItemMap[item_id]->isHidden() && !passes_filter)) + bool passes_filter = checkAgainstFilters(item, mFilterSubString); + if((item->isHidden() && passes_filter) + || (!item->isHidden() && !passes_filter)) { reArrangeRows(); } @@ -1169,7 +1181,7 @@ void LLInventoryGallery::moveUp(MASK mask) if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1) { - LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID]; + LLInventoryGalleryItem* item = getItem(mLastInteractedUUID); if (item) { if (mask == MASK_NONE || mask == MASK_CONTROL) @@ -1214,7 +1226,7 @@ void LLInventoryGallery::moveDown(MASK mask) if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1) { - LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID]; + LLInventoryGalleryItem* item = getItem(mLastInteractedUUID); if (item) { if (mask == MASK_NONE || mask == MASK_CONTROL) @@ -1259,11 +1271,7 @@ void LLInventoryGallery::moveLeft(MASK mask) if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1) { - LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID]; - if (mask == MASK_SHIFT) - { - item = mItemMap[mLastInteractedUUID]; - } + LLInventoryGalleryItem* item = getItem(mLastInteractedUUID); if (item) { // Might be better to get item from panel @@ -1307,7 +1315,7 @@ void LLInventoryGallery::moveRight(MASK mask) if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1) { - LLInventoryGalleryItem* item = mItemMap[mLastInteractedUUID]; + LLInventoryGalleryItem* item = getItem(mLastInteractedUUID); if (item) { S32 n = mItemIndexMap[item]; @@ -1373,8 +1381,8 @@ void LLInventoryGallery::toggleSelectionRangeFromLast(const LLUUID target) { return; } - LLInventoryGalleryItem* last_item = mItemMap[mLastInteractedUUID]; - LLInventoryGalleryItem* next_item = mItemMap[target]; + LLInventoryGalleryItem* last_item = getItem(mLastInteractedUUID); + LLInventoryGalleryItem* next_item = getItem(target); if (last_item && next_item) { S32 last_idx = mItemIndexMap[last_item]; @@ -1417,9 +1425,10 @@ void LLInventoryGallery::onFocusLost() for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } } @@ -1435,9 +1444,10 @@ void LLInventoryGallery::onFocusReceived() LLInventoryGalleryItem* focus_item = NULL; for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id] && !mItemMap[id]->isHidden()) + LLInventoryGalleryItem* item = getItem(id); + if (item && !item->isHidden()) { - focus_item = mItemMap[id]; + focus_item = item; focus_item->setSelected(true); } } @@ -1478,9 +1488,10 @@ void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_ { for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } mSelectedItemIDs.clear(); @@ -1499,9 +1510,10 @@ void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_ return; } - if (mItemMap[item_id]) + LLInventoryGalleryItem* item = getItem(item_id); + if (item) { - mItemMap[item_id]->setSelected(true); + item->setSelected(true); } mSelectedItemIDs.push_back(item_id); signalSelectionItemID(item_id); @@ -1527,9 +1539,10 @@ void LLInventoryGallery::addItemSelection(const LLUUID& item_id, bool scroll_to_ return; } - if (mItemMap[item_id]) + LLInventoryGalleryItem* item = getItem(item_id); + if (item) { - mItemMap[item_id]->setSelected(true); + item->setSelected(true); } mSelectedItemIDs.push_back(item_id); signalSelectionItemID(item_id); @@ -1552,18 +1565,20 @@ bool LLInventoryGallery::toggleItemSelection(const LLUUID& item_id, bool scroll_ selection_deque::iterator found = std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id); if (found != mSelectedItemIDs.end()) { - if (mItemMap[item_id]) + LLInventoryGalleryItem* item = getItem(item_id); + if (item) { - mItemMap[item_id]->setSelected(false); + item->setSelected(false); } mSelectedItemIDs.erase(found); result = false; } else { - if (mItemMap[item_id]) + LLInventoryGalleryItem* item = getItem(item_id); + if (item) { - mItemMap[item_id]->setSelected(true); + item->setSelected(true); } mSelectedItemIDs.push_back(item_id); signalSelectionItemID(item_id); @@ -1580,7 +1595,7 @@ bool LLInventoryGallery::toggleItemSelection(const LLUUID& item_id, bool scroll_ void LLInventoryGallery::scrollToShowItem(const LLUUID& item_id) { - LLInventoryGalleryItem* item = mItemMap[item_id]; + LLInventoryGalleryItem* item = getItem(item_id); if(item) { const LLRect visible_content_rect = mScrollPanel->getVisibleContentRect(); @@ -1610,7 +1625,7 @@ LLInventoryGalleryItem* LLInventoryGallery::getFirstSelectedItem() if (mSelectedItemIDs.size() > 0) { selection_deque::iterator iter = mSelectedItemIDs.begin(); - return mItemMap[*iter]; + return getItem(*iter); } return NULL; } @@ -1768,9 +1783,10 @@ void LLInventoryGallery::paste() { for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } mSelectedItemIDs.clear(); @@ -2108,9 +2124,10 @@ void LLInventoryGallery::pasteAsLink() { for (const LLUUID& id : mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } mSelectedItemIDs.clear(); @@ -2433,10 +2450,10 @@ void LLInventoryGallery::onGesturesChanged() void LLInventoryGallery::deselectItem(const LLUUID& category_id) { // Reset selection if the item is selected. - LLInventoryGalleryItem* item = mItemMap[category_id]; + LLInventoryGalleryItem* item = getItem(category_id); if (item && item->isSelected()) { - mItemMap[category_id]->setSelected(false); + item->setSelected(false); setFocus(true); // Todo: support multiselect // signalSelectionItemID(LLUUID::null); @@ -2453,9 +2470,10 @@ void LLInventoryGallery::clearSelection() { for (const LLUUID& id: mSelectedItemIDs) { - if (mItemMap[id]) + LLInventoryGalleryItem* item = getItem(id); + if (item) { - mItemMap[id]->setSelected(false); + item->setSelected(false); } } if (!mSelectedItemIDs.empty()) diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h index afc7bdc9f8..59d08d19ed 100644 --- a/indra/newview/llinventorygallery.h +++ b/indra/newview/llinventorygallery.h @@ -228,6 +228,7 @@ private: void updateGalleryWidth(); LLInventoryGalleryItem* buildGalleryItem(std::string name, LLUUID item_id, LLAssetType::EType type, LLUUID thumbnail_id, LLInventoryType::EType inventory_type, U32 flags, time_t creation_date, bool is_link, bool is_worn); + LLInventoryGalleryItem* getItem(const LLUUID& id) const; void buildGalleryPanel(int row_count); void reshapeGalleryPanel(int row_count); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 43bfe76b7f..4106ce8186 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -643,7 +643,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve } // Select any newly created object that has the auto rename at top of folder root set. - if(mFolderRoot.get()->getRoot()->needsAutoRename()) + if(mFolderRoot.get() && mFolderRoot.get()->getRoot()->needsAutoRename()) { setSelection(item_id, false); } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 6ab5e05b7d..ce0c460f5b 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -671,15 +671,16 @@ void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) if (override_mat) { // do not create a new material, reuse existing pointer - LLFetchedGLTFMaterial* render_mat = (LLFetchedGLTFMaterial*)entry->getGLTFRenderMaterial(); + LLFetchedGLTFMaterial* render_mat = dynamic_cast<LLFetchedGLTFMaterial*>(entry->getGLTFRenderMaterial()); if (render_mat) { - llassert(dynamic_cast<LLFetchedGLTFMaterial*>(entry->getGLTFRenderMaterial()) != nullptr); - { - *render_mat = *fetched_mat; - } + *render_mat = *fetched_mat; render_mat->applyOverride(*override_mat); } + else + { + LL_WARNS_ONCE() << "Failed to apply local material override, render material not found" << LL_ENDL; + } } } } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 96be917019..22420e8896 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -128,7 +128,7 @@ void LLOutfitGallery::onOpen(const LLSD& info) mScrollPanel->addChild(mGalleryPanel); for (int i = 0; i < n; i++) { - addToGallery(mOutfitMap[cats[i]]); + addToGallery(getItem(cats[i])); } reArrangeRows(); mGalleryCreated = true; @@ -377,7 +377,7 @@ void LLOutfitGallery::onOutfitsRemovalConfirmation(const LLSD& notification, con void LLOutfitGallery::scrollToShowItem(const LLUUID& item_id) { - LLOutfitGalleryItem* item = mOutfitMap[item_id]; + LLOutfitGalleryItem* item = getItem(item_id); if (item) { const LLRect visible_content_rect = mScrollPanel->getVisibleContentRect(); @@ -524,6 +524,10 @@ LLPanel* LLOutfitGallery::addToRow(LLPanel* row_stack, LLOutfitGalleryItem* item void LLOutfitGallery::addToGallery(LLOutfitGalleryItem* item) { + if (!item) + { + return; + } if(item->isHidden()) { mHiddenItems.push_back(item); @@ -631,9 +635,19 @@ LLOutfitGalleryItem* LLOutfitGallery::buildGalleryItem(std::string name, LLUUID return gitem; } -LLOutfitGalleryItem* LLOutfitGallery::getSelectedItem() +LLOutfitGalleryItem* LLOutfitGallery::getSelectedItem() const +{ + return getItem(mSelectedOutfitUUID); +} + +LLOutfitGalleryItem* LLOutfitGallery::getItem(const LLUUID& id) const { - return mOutfitMap[mSelectedOutfitUUID]; + auto it = mOutfitMap.find(id); + if (it != mOutfitMap.end()) + { + return it->second; + } + return nullptr; } void LLOutfitGallery::buildGalleryPanel(int row_count) @@ -1264,7 +1278,15 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) } if (asset_id.notNull()) { - photo_loaded |= mOutfitMap[category_id]->setImageAssetId(asset_id); + LLOutfitGalleryItem* item = getItem(category_id); + if (item) + { + photo_loaded |= item->setImageAssetId(asset_id); + } + else + { + photo_loaded = true; + } // Rename links if (!mOutfitRenamePending.isNull() && mOutfitRenamePending.asString() == item_name) { @@ -1290,13 +1312,21 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) } if (!photo_loaded) { - mOutfitMap[category_id]->setDefaultImage(); + LLOutfitGalleryItem* item = getItem(category_id); + if (item) + { + item->setDefaultImage(); + } } } } else { - mOutfitMap[category_id]->setImageAssetId(asset_id); + LLOutfitGalleryItem* item = getItem(category_id); + if (item) + { + item->setImageAssetId(asset_id); + } } } diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index d921a7fe72..819d09dcf5 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -135,7 +135,8 @@ private: void updateGalleryWidth(); LLOutfitGalleryItem* buildGalleryItem(std::string name, LLUUID outfit_id); - LLOutfitGalleryItem* getSelectedItem(); + LLOutfitGalleryItem* getSelectedItem() const; + LLOutfitGalleryItem* getItem(const LLUUID& id) const; void onTextureSelectionChanged(LLInventoryItem* itemp); diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index e6421d8a41..488bd87272 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -126,29 +126,31 @@ void LLOutputMonitorCtrl::draw() const F32 LEVEL_1 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL * 2.f / 3.f; const F32 LEVEL_2 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL; + LLVoiceClient* vocie_client = LLVoiceClient::getInstance(); + if (getVisible() && mAutoUpdate && !getIsMuted() && mSpeakerId.notNull()) { - setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId)); + setPower(vocie_client->getCurrentPower(mSpeakerId)); if(mIsAgentControl) { - setIsTalking(LLVoiceClient::getInstance()->getUserPTTState()); + setIsTalking(vocie_client->getUserPTTState()); } else { - setIsTalking(LLVoiceClient::getInstance()->getIsSpeaking(mSpeakerId)); + setIsTalking(vocie_client->getIsSpeaking(mSpeakerId)); } } if ((mPower == 0.f && !mIsTalking) && mShowParticipantsSpeaking) { std::set<LLUUID> participant_uuids; - LLVoiceClient::instance().getParticipantList(participant_uuids); + vocie_client->getParticipantList(participant_uuids); std::set<LLUUID>::const_iterator part_it = participant_uuids.begin(); F32 power = 0; for (; part_it != participant_uuids.end(); ++part_it) { - power = LLVoiceClient::instance().getCurrentPower(*part_it); + power = vocie_client->getCurrentPower(*part_it); if (power) { mPower = power; diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 519f157973..4aa4b13f2c 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -98,10 +98,7 @@ LLPanelGroup::LLPanelGroup() LLPanelGroup::~LLPanelGroup() { LLGroupMgr::getInstance()->removeObserver(this); - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + LLVoiceClient::removeObserver(this); } void LLPanelGroup::onOpen(const LLSD& key) @@ -194,7 +191,7 @@ bool LLPanelGroup::postBuild() mJoinText = panel_general->getChild<LLUICtrl>("join_cost_text"); } - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); return true; } diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 99133d1fb3..fb7ccbfe4c 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -647,10 +647,18 @@ bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const if ("collapse_all" == command_name) { + if (!mCurrentSelectedList) + { + return false; + } return has_expanded_folders(mCurrentSelectedList->getRootFolder()); } else if ("expand_all" == command_name) { + if (!mCurrentSelectedList) + { + return false; + } return has_collapsed_folders(mCurrentSelectedList->getRootFolder()); } else if ("sort_by_date" == command_name) @@ -959,12 +967,12 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold // then ask LLFolderView permissions - LLFolderView* root_folder = mCurrentSelectedList->getRootFolder(); + LLFolderView* root_folder = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : nullptr; if ("copy" == command_name) { // we shouldn't be able to copy folders from My Inventory Panel - return can_be_modified && root_folder->canCopy(); + return can_be_modified && root_folder && root_folder->canCopy(); } else if ("collapse" == command_name) { @@ -981,7 +989,7 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold if ("cut" == command_name) { - can_be_modified = root_folder->canCut(); + can_be_modified = root_folder && root_folder->canCut(); } else if ("rename" == command_name) { @@ -993,7 +1001,7 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold } else if("paste" == command_name) { - can_be_modified = root_folder->canPaste(); + can_be_modified = root_folder && root_folder->canPaste(); } else { diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 28303f3c0d..0e8036eea6 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -338,7 +338,7 @@ public: LLAvatarTracker::instance().addObserver(this); // For notification when SIP online status changes. - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); mInvObserver = new LLInventoryFriendCardObserver(this); } @@ -346,10 +346,7 @@ public: { // will be deleted by ~LLInventoryModel //delete mInvObserver; - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + LLVoiceClient::removeObserver(this); LLAvatarTracker::instance().removeObserver(this); } @@ -577,15 +574,13 @@ LLPanelPeople::~LLPanelPeople() delete mFriendListUpdater; delete mRecentListUpdater; + LLVoiceClient::removeObserver(this); + mNearbyFilterCommitConnection.disconnect(); mFriedsFilterCommitConnection.disconnect(); mGroupsFilterCommitConnection.disconnect(); mRecentFilterCommitConnection.disconnect(); - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } } void LLPanelPeople::onFriendsAccordionExpandedCollapsed(LLUICtrl* ctrl, const LLSD& param, LLAvatarList* avatar_list) @@ -726,7 +721,7 @@ bool LLPanelPeople::postBuild() // Must go after setting commit callback and initializing all pointers to children. mTabContainer->selectTabByName(NEARBY_TAB_NAME); - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 3bec7abdaf..4e74a19adb 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -703,10 +703,7 @@ LLPanelProfileSecondLife::~LLPanelProfileSecondLife() LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); } - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); - } + LLVoiceClient::removeObserver((LLVoiceClientStatusObserver*)this); if (mAvatarNameCacheConnection.connected()) { diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index c2188ea638..b7c929f0b5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -414,7 +414,13 @@ LLScriptEdCore::~LLScriptEdCore() if (script_search && script_search->getEditorCore() == this) { script_search->closeFloater(); - delete script_search; + // closeFloater can delete instance since it's not reusable nor single instance + // so make sure instance is still there before deleting + script_search = LLFloaterScriptSearch::getInstance(); + if (script_search) + { + delete script_search; + } } delete mLiveFile; diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp index 31fd6f3f07..8d164b6883 100644 --- a/indra/newview/llreflectionmap.cpp +++ b/indra/newview/llreflectionmap.cpp @@ -220,7 +220,7 @@ F32 LLReflectionMap::getNearClip() if (mViewerObject && mViewerObject->getVolume()) { - ret = ((LLVOVolume*)mViewerObject)->getReflectionProbeNearClip(); + ret = mViewerObject->getReflectionProbeNearClip(); } else if (mGroup) { @@ -240,7 +240,7 @@ bool LLReflectionMap::getIsDynamic() mViewerObject && mViewerObject->getVolume()) { - return ((LLVOVolume*)mViewerObject)->getReflectionProbeIsDynamic(); + return mViewerObject->getReflectionProbeIsDynamic(); } return false; diff --git a/indra/newview/llsculptidsize.cpp b/indra/newview/llsculptidsize.cpp index 3bc5ad7616..6be05fb003 100644 --- a/indra/newview/llsculptidsize.cpp +++ b/indra/newview/llsculptidsize.cpp @@ -29,8 +29,6 @@ #include "llvovolume.h" #include "lldrawable.h" #include "llvoavatar.h" -//boost -#include "boost/make_shared.hpp" //........... diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0456b109d7..89a803725e 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -48,7 +48,6 @@ #include <deque> #include <boost/iterator/filter_iterator.hpp> #include <boost/signals2.hpp> -#include <boost/make_shared.hpp> // boost::make_shared class LLMessageSystem; class LLViewerTexture; diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 42927769de..a02af98bbc 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -33,7 +33,6 @@ #include <algorithm> #include <cstdio> -#include <boost/make_shared.hpp> #include "lltrace.h" #include "llfasttimer.h" #include "v3colorutil.h" diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 81002139be..8fc3f1454f 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -377,16 +377,17 @@ void LLSpeakerMgr::update(bool resort_ok) } // update status of all current speakers - bool voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); + LLVoiceClient* voice_client = LLVoiceClient::getInstance(); + bool voice_channel_active = (!mVoiceChannel && voice_client->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) { LLUUID speaker_id = speaker_it->first; LLSpeaker* speakerp = speaker_it->second; - if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) + if (voice_channel_active && voice_client->getVoiceEnabled(speaker_id)) { - speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); - bool moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); + speakerp->mSpeechVolume = voice_client->getCurrentPower(speaker_id); + bool moderator_muted_voice = voice_client->getIsModeratorMuted(speaker_id); if (moderator_muted_voice != speakerp->mModeratorMutedVoice) { speakerp->mModeratorMutedVoice = moderator_muted_voice; @@ -394,11 +395,11 @@ void LLSpeakerMgr::update(bool resort_ok) speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); } - if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) + if (voice_client->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) { speakerp->mStatus = LLSpeaker::STATUS_MUTED; } - else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) + else if (voice_client->getIsSpeaking(speaker_id)) { // reset inactivity expiration if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) @@ -481,17 +482,18 @@ void LLSpeakerMgr::update(bool resort_ok) void LLSpeakerMgr::updateSpeakerList() { // Are we bound to the currently active voice channel? - if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) + LLVoiceClient* vocie_client = LLVoiceClient::getInstance(); + if ((!mVoiceChannel && vocie_client->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) { std::set<LLUUID> participants; - LLVoiceClient::getInstance()->getParticipantList(participants); + vocie_client->getParticipantList(participants); // If we are, add all voice client participants to our list of known speakers for (std::set<LLUUID>::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) { setSpeaker(*participant_it, - LLVoiceClient::getInstance()->getDisplayName(*participant_it), + vocie_client->getDisplayName(*participant_it), LLSpeaker::STATUS_VOICE_ACTIVE, - (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); + (vocie_client->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); } } else if (mVoiceChannel) diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index ca99d351bb..a9ef5e244d 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -182,7 +182,7 @@ void SpeakingIndicatorManager::unregisterSpeakingIndicator(const LLUUID& speaker SpeakingIndicatorManager::SpeakingIndicatorManager() { LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&SpeakingIndicatorManager::sOnCurrentChannelChanged, this, _1)); - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); } SpeakingIndicatorManager::~SpeakingIndicatorManager() @@ -193,10 +193,7 @@ void SpeakingIndicatorManager::cleanupSingleton() { // Don't use LLVoiceClient::getInstance() here without a check, // singleton MAY have already been destroyed. - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + LLVoiceClient::removeObserver(this); } void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_id*/) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index cd6e780aa8..862bb3dfa9 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -263,12 +263,15 @@ static bool handleAnisotropicChanged(const LLSD& newvalue) static bool handleVSyncChanged(const LLSD& newvalue) { LLPerfStats::tunables.vsyncEnabled = newvalue.asBoolean(); - gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean()); - - if (newvalue.asBoolean()) + if (gViewerWindow && gViewerWindow->getWindow()) { - U32 current_target = gSavedSettings.getU32("TargetFPS"); - gSavedSettings.setU32("TargetFPS", std::min((U32)gViewerWindow->getWindow()->getRefreshRate(), current_target)); + gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean()); + + if (newvalue.asBoolean()) + { + U32 current_target = gSavedSettings.getU32("TargetFPS"); + gSavedSettings.setU32("TargetFPS", std::min((U32)gViewerWindow->getWindow()->getRefreshRate(), current_target)); + } } return true; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 1231c52fd4..3a2d1c400b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1757,9 +1757,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ bool javascript_enabled = gSavedSettings.getBOOL("BrowserJavascriptEnabled"); media_source->setJavascriptEnabled(javascript_enabled || clean_browser); - // collect 'web security disabled' (see Chrome --web-security-disabled) setting from prefs and send to embedded browser - bool web_security_disabled = gSavedSettings.getBOOL("BrowserWebSecurityDisabled"); - media_source->setWebSecurityDisabled(web_security_disabled || clean_browser); + media_source->setWebSecurityDisabled(clean_browser); // collect setting indicates if local file access from file URLs is allowed from prefs and send to embedded browser bool file_access_from_file_urls = gSavedSettings.getBOOL("BrowserFileAccessFromFileUrls"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 5a32f9654d..0d5482dcd1 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3602,7 +3602,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) U32 local_id; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); + gObjectList.getUUIDFromLocal(id, local_id, ip, port); if (id == LLUUID::null) { LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 99a77c5551..8ea5ee33f3 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1940,14 +1940,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if(mesgsys != NULL) { - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + gObjectList.getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort()); } else { - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + gObjectList.getUUIDFromLocal(parent_uuid, parent_id, mRegionp->getHost().getAddress(), mRegionp->getHost().getPort()); @@ -2062,7 +2062,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Debugging for suspected problems with local ids. //LLUUID parent_uuid; - //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); + //gObjectList.getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); //if (parent_uuid != cur_parentp->getID() ) //{ // LL_ERRS() << "Local ID match but UUID mismatch of viewer object" << LL_ENDL; @@ -2085,14 +2085,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if(mesgsys != NULL) { - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + gObjectList.getUUIDFromLocal(parent_uuid, parent_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); } else { - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + gObjectList.getUUIDFromLocal(parent_uuid, parent_id, mRegionp->getHost().getAddress(), mRegionp->getHost().getPort()); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 08c81c4b6c..09f813accc 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -266,7 +266,11 @@ public: virtual bool isRiggedMesh() const { return false; } virtual bool hasLightTexture() const { return false; } virtual bool isReflectionProbe() const { return false; } + virtual F32 getReflectionProbeAmbiance() const { return 0.f; } + virtual F32 getReflectionProbeNearClip() const { return 0.f; } virtual bool getReflectionProbeIsBox() const { return false; } + virtual bool getReflectionProbeIsDynamic() const { return false; }; + virtual bool getReflectionProbeIsMirror() const { return false; }; // This method returns true if the object is over land owned by // the agent, one of its groups, or it encroaches and diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 08a1ba0f9b..bfbb701a8e 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -99,8 +99,6 @@ extern LLPipeline gPipeline; // Statics for object lookup tables. U32 LLViewerObjectList::sSimulatorMachineIndex = 1; // Not zero deliberately, to speed up index check. -std::map<U64, U32> LLViewerObjectList::sIPAndPortToIndex; -std::map<U64, LLUUID> LLViewerObjectList::sIndexAndLocalIDToUUID; LLViewerObjectList::LLViewerObjectList() { @@ -138,17 +136,17 @@ void LLViewerObjectList::getUUIDFromLocal(LLUUID &id, { U64 ipport = (((U64)ip) << 32) | (U64)port; - U32 index = sIPAndPortToIndex[ipport]; + U32 index = mIPAndPortToIndex[ipport]; if (!index) { index = sSimulatorMachineIndex++; - sIPAndPortToIndex[ipport] = index; + mIPAndPortToIndex[ipport] = index; } U64 indexid = (((U64)index) << 32) | (U64)local_id; - id = get_if_there(sIndexAndLocalIDToUUID, indexid, LLUUID::null); + id = get_if_there(mIndexAndLocalIDToUUID, indexid, LLUUID::null); } U64 LLViewerObjectList::getIndex(const U32 local_id, @@ -157,7 +155,7 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, { U64 ipport = (((U64)ip) << 32) | (U64)port; - U32 index = sIPAndPortToIndex[ipport]; + U32 index = mIPAndPortToIndex[ipport]; if (!index) { @@ -177,14 +175,14 @@ bool LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) U32 ip = objectp->getRegion()->getHost().getAddress(); U32 port = objectp->getRegion()->getHost().getPort(); U64 ipport = (((U64)ip) << 32) | (U64)port; - U32 index = sIPAndPortToIndex[ipport]; + U32 index = mIPAndPortToIndex[ipport]; // LL_INFOS() << "Removing object from table, local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; U64 indexid = (((U64)index) << 32) | (U64)local_id; - std::map<U64, LLUUID>::iterator iter = sIndexAndLocalIDToUUID.find(indexid); - if (iter == sIndexAndLocalIDToUUID.end()) + std::map<U64, LLUUID>::iterator iter = mIndexAndLocalIDToUUID.find(indexid); + if (iter == mIndexAndLocalIDToUUID.end()) { return false; } @@ -192,7 +190,7 @@ bool LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) // Found existing entry if (iter->second == objectp->getID()) { // Full UUIDs match, so remove the entry - sIndexAndLocalIDToUUID.erase(iter); + mIndexAndLocalIDToUUID.erase(iter); return true; } // UUIDs did not match - this would zap a valid entry, so don't erase it @@ -210,17 +208,17 @@ void LLViewerObjectList::setUUIDAndLocal(const LLUUID &id, { U64 ipport = (((U64)ip) << 32) | (U64)port; - U32 index = sIPAndPortToIndex[ipport]; + U32 index = mIPAndPortToIndex[ipport]; if (!index) { index = sSimulatorMachineIndex++; - sIPAndPortToIndex[ipport] = index; + mIPAndPortToIndex[ipport] = index; } U64 indexid = (((U64)index) << 32) | (U64)local_id; - sIndexAndLocalIDToUUID[indexid] = id; + mIndexAndLocalIDToUUID[indexid] = id; //LL_INFOS() << "Adding object to table, full ID " << id // << ", local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index f0f236d6ae..ebdfd0d369 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -171,18 +171,18 @@ public: // used to discount stats from this frame bool mWasPaused; - static void getUUIDFromLocal(LLUUID &id, + void getUUIDFromLocal(LLUUID &id, const U32 local_id, const U32 ip, const U32 port); - static void setUUIDAndLocal(const LLUUID &id, + void setUUIDAndLocal(const LLUUID &id, const U32 local_id, const U32 ip, const U32 port); // Requires knowledge of message system info! - static bool removeFromLocalIDTable(const LLViewerObject* objectp); + bool removeFromLocalIDTable(const LLViewerObject* objectp); // Used ONLY by the orphaned object code. - static U64 getIndex(const U32 local_id, const U32 ip, const U32 port); + U64 getIndex(const U32 local_id, const U32 ip, const U32 port); S32 mNumUnknownUpdates; S32 mNumDeadObjectUpdates; @@ -216,9 +216,9 @@ protected: S32 mCurLazyUpdateIndex; static U32 sSimulatorMachineIndex; - static std::map<U64, U32> sIPAndPortToIndex; + std::map<U64, U32> mIPAndPortToIndex; - static std::map<U64, LLUUID> sIndexAndLocalIDToUUID; + std::map<U64, LLUUID> mIndexAndLocalIDToUUID; friend class LLViewerObject; @@ -257,7 +257,7 @@ extern LLViewerObjectList gObjectList; */ inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) { - std::map<LLUUID, LLPointer<LLViewerObject> >::iterator iter = mUUIDObjectMap.find(id); + auto iter = mUUIDObjectMap.find(id); if(iter != mUUIDObjectMap.end()) { return iter->second; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c1062b9a01..22c7c195c4 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -805,7 +805,7 @@ S32 LLViewerTexture::getTotalNumFaces() const S32 LLViewerTexture::getNumFaces(U32 ch) const { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); - return mNumFaces[ch]; + return ch < LLRender::NUM_TEXTURE_CHANNELS ? mNumFaces[ch] : 0; } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f842e1f74c..ffba4756fc 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1271,7 +1271,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi LLTextureEntry *te = obj->getTE(object_face); // can modify URL if we can modify the object or we have navigate permissions - bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT ); + bool allow_modify_url = obj->permModify() || (te && obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT )); if (te && allow_modify_url ) { diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 912b5a330e..eb1cd00940 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -81,10 +81,7 @@ LLVoiceChannel::~LLVoiceChannel() { sCurrentVoiceChannel = NULL; // Must check instance exists here, the singleton MAY have already been destroyed. - if(LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver(this); - } + LLVoiceClient::removeObserver(this); } sVoiceChannelMap.erase(mSessionID); @@ -118,6 +115,12 @@ void LLVoiceChannel::setChannelInfo(const LLSD &channelInfo) } } +void LLVoiceChannel::resetChannelInfo() +{ + mChannelInfo = LLSD(); + mState = STATE_NO_CHANNEL_INFO; +} + void LLVoiceChannel::onChange(EStatusType type, const LLSD& channelInfo, bool proximal) { LL_DEBUGS("Voice") << "Incoming channel info: " << channelInfo << LL_ENDL; @@ -187,13 +190,13 @@ void LLVoiceChannel::handleError(EStatusType type) setState(STATE_ERROR); } -bool LLVoiceChannel::isActive() +bool LLVoiceChannel::isActive() const { // only considered active when currently bound channel matches what our channel return callStarted() && LLVoiceClient::getInstance()->isCurrentChannel(mChannelInfo); } -bool LLVoiceChannel::callStarted() +bool LLVoiceChannel::callStarted() const { return mState >= STATE_CALL_STARTED; } @@ -219,7 +222,7 @@ void LLVoiceChannel::deactivate() LLVoiceClient::getInstance()->setUserPTTState(false); } } - LLVoiceClient::getInstance()->removeObserver(this); + LLVoiceClient::removeObserver(this); if (sCurrentVoiceChannel == this) { @@ -259,7 +262,7 @@ void LLVoiceChannel::activate() setState(STATE_CALL_STARTED); } - LLVoiceClient::getInstance()->addObserver(this); + LLVoiceClient::addObserver(this); //do not send earlier, channel should be initialized, should not be in STATE_NO_CHANNEL_INFO state sCurrentVoiceChannelChangedSignal(this->mSessionID); @@ -662,7 +665,7 @@ LLVoiceChannelProximal::LLVoiceChannelProximal() : { } -bool LLVoiceChannelProximal::isActive() +bool LLVoiceChannelProximal::isActive() const { return callStarted() && LLVoiceClient::getInstance()->inProximalChannel(); } @@ -751,7 +754,7 @@ void LLVoiceChannelProximal::deactivate() { setState(STATE_HUNG_UP); } - LLVoiceClient::getInstance()->removeObserver(this); + LLVoiceClient::removeObserver(this); LLVoiceClient::getInstance()->activateSpatialChannel(false); } @@ -918,6 +921,12 @@ void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info) } } +void LLVoiceChannelP2P::resetChannelInfo() +{ + mChannelInfo = LLVoiceClient::getInstance()->getP2PChannelInfoTemplate(mOtherUserID); + mState = STATE_NO_CHANNEL_INFO; // we have template, not full info +} + void LLVoiceChannelP2P::setState(EState state) { LL_INFOS("Voice") << "P2P CALL STATE CHANGE: incoming=" << int(mReceivedCall) << " oldstate=" << mState << " newstate=" << state << LL_ENDL; diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 6af1bd57a3..4d7bf551e1 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -72,10 +72,11 @@ public: virtual void handleError(EStatusType status); virtual void deactivate(); virtual void activate(); - virtual void setChannelInfo(const LLSD &channelInfo); + virtual void setChannelInfo(const LLSD& channelInfo); + virtual void resetChannelInfo(); virtual void requestChannelInfo(); - virtual bool isActive(); - virtual bool callStarted(); + virtual bool isActive() const; + virtual bool callStarted() const; // Session name is a UI label used for feedback about which person, // group, or phone number you are talking to @@ -170,7 +171,7 @@ class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoice void onChange(EStatusType status, const LLSD &channelInfo, bool proximal) override; void handleStatusChange(EStatusType status) override; void handleError(EStatusType status) override; - bool isActive() override; + bool isActive() const override; void activate() override; void deactivate() override; }; @@ -189,6 +190,7 @@ class LLVoiceChannelP2P : public LLVoiceChannelGroup void requestChannelInfo() override; void deactivate() override; void setChannelInfo(const LLSD& channel_info) override; + void resetChannelInfo() override; protected: void setState(EState state) override; diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 3a07e4bb90..e8d64cabf6 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -289,10 +289,8 @@ void LLVoiceClient::setNonSpatialVoiceModule(const std::string &voice_server_typ void LLVoiceClient::setHidden(bool hidden) { - if (mSpatialVoiceModule) - { - mSpatialVoiceModule->setHidden(hidden); - } + LLWebRTCVoiceClient::getInstance()->setHidden(hidden); + LLVivoxVoiceClient::getInstance()->setHidden(hidden); } void LLVoiceClient::terminate() @@ -462,7 +460,7 @@ const LLVoiceDeviceList& LLVoiceClient::getRenderDevices() //-------------------------------------------------- // participants -void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) +void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) const { #if !__FreeBSD__ LLWebRTCVoiceClient::getInstance()->getParticipantList(participants); @@ -470,7 +468,7 @@ void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants) LLVivoxVoiceClient::getInstance()->getParticipantList(participants); } -bool LLVoiceClient::isParticipant(const LLUUID &speaker_id) +bool LLVoiceClient::isParticipant(const LLUUID &speaker_id) const { return #if !__FreeBSD__ @@ -791,12 +789,12 @@ void LLVoiceClient::toggleUserPTTState(void) //------------------------------------------- // nearby speaker accessors -bool LLVoiceClient::getVoiceEnabled(const LLUUID& id) +bool LLVoiceClient::getVoiceEnabled(const LLUUID& id) const { return isParticipant(id); } -std::string LLVoiceClient::getDisplayName(const LLUUID& id) +std::string LLVoiceClient::getDisplayName(const LLUUID& id) const { #if __FreeBSD__ return LLVivoxVoiceClient::getInstance()->getDisplayName(id); @@ -897,9 +895,15 @@ void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer) void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer) { - LLVivoxVoiceClient::getInstance()->removeObserver(observer); + if (LLVivoxVoiceClient::instanceExists()) + { + LLVivoxVoiceClient::getInstance()->removeObserver(observer); + } #if !__FreeBSD__ - LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + if (LLWebRTCVoiceClient::instanceExists()) + { + LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + } #endif } @@ -913,9 +917,15 @@ void LLVoiceClient::addObserver(LLFriendObserver* observer) void LLVoiceClient::removeObserver(LLFriendObserver* observer) { - LLVivoxVoiceClient::getInstance()->removeObserver(observer); + if (LLVivoxVoiceClient::instanceExists()) + { + LLVivoxVoiceClient::getInstance()->removeObserver(observer); + } #if !__FreeBSD__ - LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + if (LLWebRTCVoiceClient::instanceExists()) + { + LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + } #endif } @@ -929,9 +939,15 @@ void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer) { - LLVivoxVoiceClient::getInstance()->removeObserver(observer); + if (LLVivoxVoiceClient::instanceExists()) + { + LLVivoxVoiceClient::getInstance()->removeObserver(observer); + } #if !__FreeBSD__ - LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + if (LLWebRTCVoiceClient::instanceExists()) + { + LLWebRTCVoiceClient::getInstance()->removeObserver(observer); + } #endif } diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index ea67500109..c989b1f5d9 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -133,7 +133,7 @@ class LLVoiceP2PIncomingCallInterface virtual void declineInvite() = 0; }; -typedef boost::shared_ptr<LLVoiceP2PIncomingCallInterface> LLVoiceP2PIncomingCallInterfacePtr; +typedef std::shared_ptr<LLVoiceP2PIncomingCallInterface> LLVoiceP2PIncomingCallInterfacePtr; ////////////////////////////////// /// @class LLVoiceModuleInterface @@ -452,8 +452,8 @@ public: ///////////////////////////// // Accessors for data related to nearby speakers - bool getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar - std::string getDisplayName(const LLUUID& id); + bool getVoiceEnabled(const LLUUID& id) const; // true if we've received data for this avatar + std::string getDisplayName(const LLUUID& id) const; bool isOnlineSIP(const LLUUID &id); bool isParticipantAvatar(const LLUUID &id); bool getIsSpeaking(const LLUUID& id); @@ -463,8 +463,8 @@ public: F32 getUserVolume(const LLUUID& id); ///////////////////////////// - void getParticipantList(std::set<LLUUID> &participants); - bool isParticipant(const LLUUID& speaker_id); + void getParticipantList(std::set<LLUUID> &participants) const; + bool isParticipant(const LLUUID& speaker_id) const; ////////////////////////// /// @name text chat @@ -482,12 +482,12 @@ public: void onRegionChanged(); - void addObserver(LLVoiceClientStatusObserver* observer); - void removeObserver(LLVoiceClientStatusObserver* observer); - void addObserver(LLFriendObserver* observer); - void removeObserver(LLFriendObserver* observer); - void addObserver(LLVoiceClientParticipantObserver* observer); - void removeObserver(LLVoiceClientParticipantObserver* observer); + static void addObserver(LLVoiceClientStatusObserver* observer); + static void removeObserver(LLVoiceClientStatusObserver* observer); + static void addObserver(LLFriendObserver* observer); + static void removeObserver(LLFriendObserver* observer); + static void addObserver(LLVoiceClientParticipantObserver* observer); + static void removeObserver(LLVoiceClientParticipantObserver* observer); std::string sipURIFromID(const LLUUID &id) const; LLSD getP2PChannelInfoTemplate(const LLUUID& id) const; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 532633754f..90f0f2eba9 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -2161,7 +2161,6 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInChannel = true; mMuteMicDirty = true; - mSessionTerminateRequested = false; while (!sShuttingDown && mVoiceEnabled @@ -4986,7 +4985,7 @@ void LLVivoxVoiceClient::hangup() { leaveChannel(); } LLVoiceP2PIncomingCallInterfacePtr LLVivoxVoiceClient::getIncomingCallInterface(const LLSD &voice_call_info) { - return boost::make_shared<LLVivoxVoiceP2PIncomingCall>(voice_call_info); + return std::make_shared<LLVivoxVoiceP2PIncomingCall>(voice_call_info); } bool LLVivoxVoiceClient::answerInvite(const std::string &sessionHandle) @@ -5110,7 +5109,9 @@ void LLVivoxVoiceClient::processChannels(bool process) bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo) { - if (!mProcessChannels || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE)) + if (!mProcessChannels + || (channelInfo.has("voice_server_type") && channelInfo["voice_server_type"].asString() != VIVOX_VOICE_SERVER_TYPE) + || mSessionTerminateRequested) { return false; } @@ -5447,8 +5448,8 @@ void LLVivoxVoiceClient::leaveChannel(void) { LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL; mChannelName.clear(); - sessionTerminate(); } + sessionTerminate(); } void LLVivoxVoiceClient::setMuteMic(bool muted) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index c40c84cef3..f94da7bd7a 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -91,6 +91,8 @@ public: // Returns true if vivox has successfully logged in and is not in error state bool isVoiceWorking() const override; + void setHidden(bool hidden) override; // virtual + ///////////////////// /// @name Tuning //@{ @@ -762,7 +764,6 @@ private: LLSD getAudioSessionChannelInfo(); std::string getAudioSessionHandle(); - void setHidden(bool hidden) override; //virtual void sendPositionAndVolumeUpdate(void); void sendCaptureAndRenderDevices(); diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 617981c3aa..679df094cf 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -239,11 +239,26 @@ LLWebRTCVoiceClient::LLWebRTCVoiceClient() : LLWebRTCVoiceClient::~LLWebRTCVoiceClient() { +} + +void LLWebRTCVoiceClient::cleanupSingleton() +{ if (mAvatarNameCacheConnection.connected()) { mAvatarNameCacheConnection.disconnect(); } + sShuttingDown = true; + if (mSession) + { + mSession->shutdownAllConnections(); + } + if (mNextSession) + { + mNextSession->shutdownAllConnections(); + } + cleanUp(); + sessionState::clearSessions(); } //--------------------------------------------------- @@ -256,6 +271,7 @@ void LLWebRTCVoiceClient::init(LLPumpIO* pump) mWebRTCDeviceInterface = llwebrtc::getDeviceInterface(); mWebRTCDeviceInterface->setDevicesObserver(this); mMainQueue = LL::WorkQueue::getInstance("mainloop"); + refreshDeviceLists(); } void LLWebRTCVoiceClient::terminate() @@ -460,6 +476,7 @@ void LLWebRTCVoiceClient::voiceConnectionCoro() // Could help with voice updates making for smoother // voice when we're busy. llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); + if (sShuttingDown) return; // 'this' migh already be invalid bool voiceEnabled = mVoiceEnabled; if (!isAgentAvatarValid()) @@ -623,7 +640,7 @@ void LLWebRTCVoiceClient::clearCaptureDevices() void LLWebRTCVoiceClient::addCaptureDevice(const LLVoiceDevice& device) { - LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL; + LL_INFOS("Voice") << "Voice Capture Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL; mCaptureDevices.push_back(device); } @@ -656,6 +673,10 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices, const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices) { + if (sShuttingDown) + { + return; + } LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice"); std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); @@ -688,7 +709,7 @@ void LLWebRTCVoiceClient::clearRenderDevices() void LLWebRTCVoiceClient::addRenderDevice(const LLVoiceDevice& device) { - LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL; + LL_INFOS("Voice") << "Voice Render Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL; mRenderDevices.push_back(device); } @@ -1256,7 +1277,7 @@ void LLWebRTCVoiceClient::sessionState::removeParticipant(const LLWebRTCVoiceCli LLWebRTCVoiceClient::getInstance()->notifyParticipantObservers(); } } - if (mHangupOnLastLeave && (participantID != gAgentID) && (mParticipantsByUUID.size() <= 1)) + if (mHangupOnLastLeave && (participantID != gAgentID) && (mParticipantsByUUID.size() <= 1) && LLWebRTCVoiceClient::instanceExists()) { LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); } @@ -1707,7 +1728,7 @@ void LLWebRTCVoiceClient::predSetUserMute(const LLWebRTCVoiceClient::sessionStat //------------------------------------------------------------------------ // Sessions -std::map<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> LLWebRTCVoiceClient::sessionState::mSessions; +std::map<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> LLWebRTCVoiceClient::sessionState::sSessions; LLWebRTCVoiceClient::sessionState::sessionState() : @@ -1794,13 +1815,19 @@ void LLWebRTCVoiceClient::sessionState::addSession( const std::string & channelID, LLWebRTCVoiceClient::sessionState::ptr_t& session) { - mSessions[channelID] = session; + sSessions[channelID] = session; } LLWebRTCVoiceClient::sessionState::~sessionState() { LL_DEBUGS("Voice") << "Destroying session CHANNEL=" << mChannelID << LL_ENDL; + if (!mShuttingDown) + { + shutdownAllConnections(); + } + mWebRTCConnections.clear(); + removeAllParticipants(); } @@ -1810,8 +1837,8 @@ LLWebRTCVoiceClient::sessionState::ptr_t LLWebRTCVoiceClient::sessionState::matc sessionStatePtr_t result; // *TODO: My kingdom for a lambda! - std::map<std::string, ptr_t>::iterator it = mSessions.find(channel_id); - if (it != mSessions.end()) + std::map<std::string, ptr_t>::iterator it = sSessions.find(channel_id); + if (it != sSessions.end()) { result = (*it).second; } @@ -1820,17 +1847,17 @@ LLWebRTCVoiceClient::sessionState::ptr_t LLWebRTCVoiceClient::sessionState::matc void LLWebRTCVoiceClient::sessionState::for_each(sessionFunc_t func) { - std::for_each(mSessions.begin(), mSessions.end(), boost::bind(for_eachPredicate, _1, func)); + std::for_each(sSessions.begin(), sSessions.end(), boost::bind(for_eachPredicate, _1, func)); } void LLWebRTCVoiceClient::sessionState::reapEmptySessions() { std::map<std::string, ptr_t>::iterator iter; - for (iter = mSessions.begin(); iter != mSessions.end();) + for (iter = sSessions.begin(); iter != sSessions.end();) { if (iter->second->isEmpty()) { - iter = mSessions.erase(iter); + iter = sSessions.erase(iter); } else { @@ -1876,6 +1903,11 @@ LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::addSession(const std } } +void LLWebRTCVoiceClient::sessionState::clearSessions() +{ + sSessions.clear(); +} + LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::findP2PSession(const LLUUID &agent_id) { sessionStatePtr_t result = sessionState::matchSessionByChannelID(agent_id.asString()); @@ -1915,14 +1947,14 @@ void LLWebRTCVoiceClient::sessionState::processSessionStates() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE - auto iter = mSessions.begin(); - while (iter != mSessions.end()) + auto iter = sSessions.begin(); + while (iter != sSessions.end()) { if (!iter->second->processConnectionStates() && iter->second->mShuttingDown) { // if the connections associated with a session are gone, // and this session is shutting down, remove it. - iter = mSessions.erase(iter); + iter = sSessions.erase(iter); } else { @@ -1967,8 +1999,8 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates() for (auto &connection : mWebRTCConnections) { - boost::shared_ptr<LLVoiceWebRTCSpatialConnection> spatialConnection = - boost::static_pointer_cast<LLVoiceWebRTCSpatialConnection>(connection); + std::shared_ptr<LLVoiceWebRTCSpatialConnection> spatialConnection = + std::static_pointer_cast<LLVoiceWebRTCSpatialConnection>(connection); LLUUID regionID = spatialConnection.get()->getRegionID(); @@ -2123,8 +2155,10 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s mOutstandingRequests(0), mChannelID(channelID), mRegionID(regionID), + mPrimary(true), mRetryWaitPeriod(0) { + // retries wait a short period...randomize it so // all clients don't try to reconnect at once. mRetryWaitSecs = ((F32) rand() / (RAND_MAX)) + 0.5; @@ -2190,47 +2224,47 @@ void LLVoiceWebRTCConnection::processIceUpdates() { mOutstandingRequests++; LLCoros::getInstance()->launch("LLVoiceWebRTCConnection::processIceUpdatesCoro", - boost::bind(&LLVoiceWebRTCConnection::processIceUpdatesCoro, this)); + boost::bind(&LLVoiceWebRTCConnection::processIceUpdatesCoro, this->shared_from_this())); } // Ice candidates may be streamed in before or after the SDP offer is available (see below) // This function determines whether candidates are available to send to the Secondlife WebRTC // server via the simulator. If so, and there are no more candidates, this code // will make the cap call to the server sending up the ICE candidates. -void LLVoiceWebRTCConnection::processIceUpdatesCoro() +void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE - if (mShutDown || LLWebRTCVoiceClient::isShuttingDown()) + if (connection->mShutDown || LLWebRTCVoiceClient::isShuttingDown()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } - //bool iceCompleted = false; + bool iceCompleted = false; LLSD body; - if (!mIceCandidates.empty() || mIceCompleted) + if (!connection->mIceCandidates.empty() || connection->mIceCompleted) { - LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(connection->mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL; - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } std::string url = regionp->getCapability("VoiceSignalingRequest"); if (url.empty()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } LL_DEBUGS("Voice") << "region ready to complete voice signaling; url=" << url << LL_ENDL; - if (!mIceCandidates.empty()) + if (!connection->mIceCandidates.empty()) { LLSD candidates = LLSD::emptyArray(); - for (auto &ice_candidate : mIceCandidates) + for (auto &ice_candidate : connection->mIceCandidates) { LLSD body_candidate; body_candidate["sdpMid"] = ice_candidate.mSdpMid; @@ -2239,18 +2273,18 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() candidates.append(body_candidate); } body["candidates"] = candidates; - mIceCandidates.clear(); + connection->mIceCandidates.clear(); } - else if (mIceCompleted) + else if (connection->mIceCompleted) { LLSD body_candidate; body_candidate["completed"] = true; body["candidate"] = body_candidate; - //iceCompleted = mIceCompleted; - mIceCompleted = false; + iceCompleted = connection->mIceCompleted; + connection->mIceCompleted = false; } - body["viewer_session"] = mViewerSession; + body["viewer_session"] = connection->mViewerSession; body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE; LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( @@ -2265,7 +2299,7 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() if (LLWebRTCVoiceClient::isShuttingDown()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } @@ -2275,10 +2309,10 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() if (!status) { // couldn't trickle the candidates, so restart the session. - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); } } - mOutstandingRequests--; + connection->mOutstandingRequests--; } @@ -2370,6 +2404,12 @@ void LLVoiceWebRTCConnection::OnPeerConnectionClosed() setVoiceConnectionState(VOICE_STATE_CLOSED); mOutstandingRequests--; } + else if (LLWebRTCVoiceClient::isShuttingDown()) + { + // disconnect was initialized by llwebrtc::terminate() instead of connectionStateMachine + LL_INFOS("Voice") << "Peer connection has closed, but state is " << mVoiceConnectionState << LL_ENDL; + setVoiceConnectionState(VOICE_STATE_CLOSED); + } }); } @@ -2424,31 +2464,31 @@ void LLVoiceWebRTCConnection::sendData(const std::string &data) // Tell the simulator that we're shutting down a voice connection. // The simulator will pass this on to the Secondlife WebRTC server. -void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() +void LLVoiceWebRTCConnection::breakVoiceConnectionCoro(connectionPtr_t connection) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE LL_DEBUGS("Voice") << "Disconnecting voice." << LL_ENDL; - if (mWebRTCDataInterface) + if (connection->mWebRTCDataInterface) { - mWebRTCDataInterface->unsetDataObserver(this); - mWebRTCDataInterface = nullptr; + connection->mWebRTCDataInterface->unsetDataObserver(connection.get()); + connection->mWebRTCDataInterface = nullptr; } - mWebRTCAudioInterface = nullptr; - LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + connection->mWebRTCAudioInterface = nullptr; + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(connection->mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); - mOutstandingRequests--; + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->mOutstandingRequests--; return; } std::string url = regionp->getCapability("ProvisionVoiceAccountRequest"); if (url.empty()) { - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); - mOutstandingRequests--; + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->mOutstandingRequests--; return; } @@ -2457,7 +2497,7 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() LLVoiceWebRTCStats::getInstance()->provisionAttemptStart(); LLSD body; body["logout"] = true; - body["viewer_session"] = mViewerSession; + body["viewer_session"] = connection->mViewerSession; body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE; LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( @@ -2468,15 +2508,19 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() httpOpts->setWantHeaders(true); - mOutstandingRequests++; + connection->mOutstandingRequests++; // tell the server to shut down the connection as a courtesy. // shutdownConnection will drop the WebRTC connection which will // also shut things down. LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts); - mOutstandingRequests--; - setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + connection->mOutstandingRequests--; + + if (connection->getVoiceConnectionState() == VOICE_STATE_WAIT_FOR_EXIT) + { + connection->setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + } } // Tell the simulator to tell the Secondlife WebRTC server that we want a voice @@ -2660,7 +2704,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() // VOICE_STATE_SESSION_ESTABLISHED via a callback on a webrtc thread. setVoiceConnectionState(VOICE_STATE_CONNECTION_WAIT); LLCoros::getInstance()->launch("LLVoiceWebRTCConnection::requestVoiceConnectionCoro", - boost::bind(&LLVoiceWebRTCConnection::requestVoiceConnectionCoro, this)); + boost::bind(&LLVoiceWebRTCConnection::requestVoiceConnectionCoro, this->shared_from_this())); break; case VOICE_STATE_CONNECTION_WAIT: @@ -2710,6 +2754,17 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { mRetryWaitPeriod = 0; mRetryWaitSecs = ((F32) rand() / (RAND_MAX)) + 0.5; + LLUUID agentRegionID; + if (isSpatial() && gAgent.getRegion()) + { + + bool primary = (mRegionID == gAgent.getRegion()->getRegionID()); + if (primary != mPrimary) + { + mPrimary = primary; + sendJoin(); + } + } // we'll stay here as long as the session remains up. if (mShutDown) @@ -2738,9 +2793,18 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() break; case VOICE_STATE_DISCONNECT: - setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); - LLCoros::instance().launch("LLVoiceWebRTCConnection::breakVoiceConnectionCoro", - boost::bind(&LLVoiceWebRTCConnection::breakVoiceConnectionCoro, this)); + if (!LLWebRTCVoiceClient::isShuttingDown()) + { + setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); + LLCoros::instance().launch("LLVoiceWebRTCConnection::breakVoiceConnectionCoro", + boost::bind(&LLVoiceWebRTCConnection::breakVoiceConnectionCoro, this->shared_from_this())); + } + else + { + // llwebrtc::terminate() is already shuting down the connection. + setVoiceConnectionState(VOICE_STATE_WAIT_FOR_CLOSE); + mOutstandingRequests++; + } break; case VOICE_STATE_WAIT_FOR_EXIT: @@ -2750,7 +2814,11 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { setVoiceConnectionState(VOICE_STATE_WAIT_FOR_CLOSE); mOutstandingRequests++; - mWebRTCPeerConnectionInterface->shutdownConnection(); + if (!LLWebRTCVoiceClient::isShuttingDown()) + { + mWebRTCPeerConnectionInterface->shutdownConnection(); + } + // else was already posted by llwebrtc::terminate(). break; case VOICE_STATE_WAIT_FOR_CLOSE: break; @@ -2980,7 +3048,7 @@ void LLVoiceWebRTCConnection::sendJoin() boost::json::object root; boost::json::object join_obj; LLUUID regionID = gAgent.getRegion()->getRegionID(); - if ((regionID == mRegionID) || !isSpatial()) + if (mPrimary) { join_obj["p"] = true; } @@ -2998,6 +3066,10 @@ LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID ® LLVoiceWebRTCConnection(regionID, channelID), mParcelLocalID(parcelLocalID) { + if (gAgent.getRegion()) + { + mPrimary = (regionID == gAgent.getRegion()->getRegionID()); + } } LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 2b9a113fcc..32127f9b17 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -55,7 +55,7 @@ class LLWebRTCProtocolParser; class LLAvatarName; class LLVoiceWebRTCConnection; -typedef boost::shared_ptr<LLVoiceWebRTCConnection> connectionPtr_t; +typedef std::shared_ptr<LLVoiceWebRTCConnection> connectionPtr_t; extern const std::string WEBRTC_VOICE_SERVER_TYPE; @@ -70,6 +70,7 @@ class LLWebRTCVoiceClient : public LLSingleton<LLWebRTCVoiceClient>, virtual ~LLWebRTCVoiceClient(); public: + void cleanupSingleton() override; /// @name LLVoiceModuleInterface virtual implementations /// @see LLVoiceModuleInterface //@{ @@ -88,6 +89,7 @@ public: std::string sipURIFromID(const LLUUID &id) const override; LLSD getP2PChannelInfoTemplate(const LLUUID& id) const override; + void setHidden(bool hidden) override; // virtual /////////////////// /// @name Logging @@ -252,7 +254,7 @@ public: bool mIsModeratorMuted; LLUUID mRegion; }; - typedef boost::shared_ptr<participantState> participantStatePtr_t; + typedef std::shared_ptr<participantState> participantStatePtr_t; participantStatePtr_t findParticipantByID(const std::string &channelID, const LLUUID &id); participantStatePtr_t addParticipantByID(const std::string& channelID, const LLUUID &id, const LLUUID& region); @@ -265,10 +267,10 @@ public: class sessionState { public: - typedef boost::shared_ptr<sessionState> ptr_t; - typedef boost::weak_ptr<sessionState> wptr_t; + typedef std::shared_ptr<sessionState> ptr_t; + typedef std::weak_ptr<sessionState> wptr_t; - typedef boost::function<void(const ptr_t &)> sessionFunc_t; + typedef std::function<void(const ptr_t &)> sessionFunc_t; static void addSession(const std::string &channelID, ptr_t& session); virtual ~sessionState(); @@ -299,6 +301,7 @@ public: static void for_each(sessionFunc_t func); static void reapEmptySessions(); + static void clearSessions(); bool isEmpty() { return mWebRTCConnections.empty(); } @@ -318,7 +321,7 @@ public: participantUUIDMap mParticipantsByUUID; static bool hasSession(const std::string &sessionID) - { return mSessions.find(sessionID) != mSessions.end(); } + { return sSessions.find(sessionID) != sSessions.end(); } bool mHangupOnLastLeave; // notify observers after the session becomes empty. bool mNotifyOnFirstJoin; // notify observers when the first peer joins. @@ -329,14 +332,14 @@ public: private: - static std::map<std::string, ptr_t> mSessions; // canonical list of outstanding sessions. + static std::map<std::string, ptr_t> sSessions; // canonical list of outstanding sessions. static void for_eachPredicate(const std::pair<std::string, LLWebRTCVoiceClient::sessionState::wptr_t> &a, sessionFunc_t func); }; - typedef boost::shared_ptr<sessionState> sessionStatePtr_t; + typedef std::shared_ptr<sessionState> sessionStatePtr_t; typedef std::map<std::string, sessionStatePtr_t> sessionMap; class estateSessionState : public sessionState @@ -480,8 +483,6 @@ private: LLSD getAudioSessionChannelInfo(); - void setHidden(bool hidden) override; //virtual - void enforceTether(); void updateNeighboringRegions(); @@ -576,7 +577,8 @@ class LLVoiceWebRTCStats : public LLSingleton<LLVoiceWebRTCStats> class LLVoiceWebRTCConnection : public llwebrtc::LLWebRTCSignalingObserver, - public llwebrtc::LLWebRTCDataObserver + public llwebrtc::LLWebRTCDataObserver, + public std::enable_shared_from_this<LLVoiceWebRTCConnection> { public: LLVoiceWebRTCConnection(const LLUUID ®ionID, const std::string &channelID); @@ -610,7 +612,7 @@ class LLVoiceWebRTCConnection : void processIceUpdates(); - void processIceUpdatesCoro(); + static void processIceUpdatesCoro(connectionPtr_t connection); virtual void setMuteMic(bool muted); virtual void setSpeakerVolume(F32 volume); @@ -620,7 +622,7 @@ class LLVoiceWebRTCConnection : bool connectionStateMachine(); - virtual bool isSpatial() = 0; + virtual bool isSpatial() { return false; } LLUUID getRegionID() { return mRegionID; } @@ -677,13 +679,14 @@ class LLVoiceWebRTCConnection : } virtual void requestVoiceConnection() = 0; - void requestVoiceConnectionCoro() { requestVoiceConnection(); } + static void requestVoiceConnectionCoro(connectionPtr_t connection) { connection->requestVoiceConnection(); } - void breakVoiceConnectionCoro(); + static void breakVoiceConnectionCoro(connectionPtr_t connection); LLVoiceClientStatusObserver::EStatusType mCurrentStatus; LLUUID mRegionID; + bool mPrimary; LLUUID mViewerSession; std::string mChannelID; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 29c510e7b3..0804f8f3c0 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5642,7 +5642,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } // HACK -- brute force this check every time a drawable gets rebuilt - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) + S32 num_tex = llmin(vobj->getNumTEs(), drawablep->getNumFaces()); + for (S32 i = 0; i < num_tex; ++i) { vobj->updateTEMaterialTextures(i); } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 07e02e042c..6241bf42d6 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -304,11 +304,11 @@ public: bool setReflectionProbeIsMirror(bool is_mirror); bool isReflectionProbe() const override; - F32 getReflectionProbeAmbiance() const; - F32 getReflectionProbeNearClip() const; + F32 getReflectionProbeAmbiance() const override; + F32 getReflectionProbeNearClip() const override; bool getReflectionProbeIsBox() const override; - bool getReflectionProbeIsDynamic() const; - bool getReflectionProbeIsMirror() const; + bool getReflectionProbeIsDynamic() const override; + bool getReflectionProbeIsMirror() const override; // Flexible Objects U32 getVolumeInterfaceID() const; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 73b001a526..1e2cb9566d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8850,6 +8850,7 @@ New Voice Morphs are available! Voice Morphs are not supported by this viewer. For more information about other voice morph tools, see [[FAQ_URL] this article]. <usetemplate + ignoretext="Warn me about voice morph not being supported" name="okignore" yestext="OK"/> <tag>voice</tag> |