From bf3e2e2b172dffbe745092a062f48bb6bc8b269f Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 13 Aug 2024 11:22:03 +0300
Subject: viewer-private#262 webrtc crashes on shutdown #2

---
 indra/newview/llvoicewebrtc.cpp | 50 ++++++++++++++++++++++++++++++++---------
 indra/newview/llvoicewebrtc.h   |  6 +++--
 2 files changed, 44 insertions(+), 12 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index ff3c0eccd2..1ee1e69b79 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -237,12 +237,27 @@ 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();
 }
 
 //---------------------------------------------------
@@ -656,6 +671,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");
@@ -1704,7 +1723,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() :
@@ -1791,13 +1810,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();
 }
 
@@ -1807,8 +1832,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;
     }
@@ -1817,17 +1842,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
         {
@@ -1873,6 +1898,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());
@@ -1912,14 +1942,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
         {
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index f699bd6df9..48c50a1ea3 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -70,6 +70,7 @@ class LLWebRTCVoiceClient : public LLSingleton<LLWebRTCVoiceClient>,
     virtual ~LLWebRTCVoiceClient();
 
 public:
+    void cleanupSingleton() override;
     /// @name LLVoiceModuleInterface virtual implementations
     ///  @see LLVoiceModuleInterface
     //@{
@@ -300,6 +301,7 @@ public:
         static void for_each(sessionFunc_t func);
 
         static void reapEmptySessions();
+        static void clearSessions();
 
         bool isEmpty() { return mWebRTCConnections.empty(); }
 
@@ -319,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.
@@ -330,7 +332,7 @@ 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,
-- 
cgit v1.2.3