diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 4335168417bc0795cda5635a4aaa38a02781c794..4cd85ac756e07c429632d85274d180731da036d6 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -357,22 +357,20 @@ void LLConversationItemSession::clearParticipants()
 
 void LLConversationItemSession::clearAndDeparentModels()
 {
-    std::for_each(mChildren.begin(), mChildren.end(),
-        [](LLFolderViewModelItem* c)
+    for (LLFolderViewModelItem* child : mChildren)
+    {
+        if (child->getNumRefs() == 0)
         {
-            if (c->getNumRefs() == 0)
-            {
-                // LLConversationItemParticipant can be created but not assigned to any view,
-                // it was waiting for an "add_participant" event to be processed
-                delete c;
-            }
-            else
-            {
-                // Model is still assigned to some view/widget
-                c->setParent(NULL);
-            }
+            // LLConversationItemParticipant can be created but not assigned to any view,
+            // it was waiting for an "add_participant" event to be processed
+            delete child;
         }
-    );
+        else
+        {
+            // Model is still assigned to some view/widget
+            child->setParent(NULL);
+        }
+    }
     mChildren.clear();
 }
 
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index dc64d09f9fe68abc3311078e1adb5cb6a832df3c..0ed84c381fa6117c16dae3f38e024e4c4fcfcd2d 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -102,6 +102,26 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
 LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
 {
     delete mRefreshTimer;
+
+    LLFloaterIMContainer* im_container = LLFloaterIMContainer::findInstance();
+    if (im_container)
+    {
+        LLParticipantList* session = dynamic_cast<LLParticipantList*>(im_container->getSessionModel(mSessionID));
+        if (session)
+        {
+            for (const conversations_widgets_map::value_type& widget_pair : mConversationsWidgets)
+            {
+                LLFolderViewItem* widget = widget_pair.second;
+                LLFolderViewModelItem* item_vmi = widget->getViewModelItem();
+                if (item_vmi && item_vmi->getNumRefs() == 1)
+                {
+                    // This is the last pointer, remove participant from session
+                    // before participant gets deleted on destroyView.
+                    session->removeChild(item_vmi);
+                }
+            }
+        }
+    }
 }
 
 // static
@@ -663,6 +683,27 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
     LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
     if (widget)
     {
+        LLFolderViewModelItem* item_vmi = widget->getViewModelItem();
+        if (item_vmi && item_vmi->getNumRefs() == 1)
+        {
+            // This is the last pointer, remove participant from session
+            // before participant gets deleted on destroyView.
+            // 
+            // Floater (widget) and participant's view can simultaneously
+            // co-own the model, in which case view is responsible for
+            // the deletion and floater is free to clear and recreate
+            // the list, yet there are cases where only widget owns
+            // the pointer so it should do the cleanup.
+            // See "add_participant".
+            //
+            // Todo: If it keeps causing issues turn participants
+            // into LLPointers in the session 
+            LLParticipantList* session = getParticipantList();
+            if (session)
+            {
+                session->removeChild(item_vmi);
+            }
+        }
         widget->destroyView();
     }
     mConversationsWidgets.erase(participant_id);
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 014dd90406428e3f19897e4347190538c614999f..d3f013c67cab6d9fb357c97c0ceb203e3e4a7cbb 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -3413,11 +3413,11 @@ LLUUID LLIMMgr::addSession(
         ((IM_NOTHING_SPECIAL == dialog) || (IM_SESSION_P2P_INVITE == dialog) || (IM_SESSION_CONFERENCE_START == dialog)) &&
         ids.size())
     {
-        LLIMModel::LLIMSession* ad_hoc_found = LLIMModel::getInstance()->findAdHocIMSession(ids);
-        if (ad_hoc_found)
+        session = LLIMModel::getInstance()->findAdHocIMSession(ids);
+        if (session)
         {
             new_session = false;
-            session_id = ad_hoc_found->mSessionID;
+            session_id = session->mSessionID;
         }
     }
 
@@ -3853,7 +3853,7 @@ bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection dir
 {
     LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id);
     if (!voice_channel) return false;
-    if (!voice_channel_info.isUndefined())
+    if (voice_channel_info.isDefined() && voice_channel_info.isMap() && voice_channel_info.size() > 0)
     {
         voice_channel->setChannelInfo(voice_channel_info);
     }
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index f6556b7128ad58b0edc9a9753f70d465ac67010b..8681411a987fe5627d3e247d7e1e871051a70c89 100644
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -96,7 +96,7 @@ void LLVoiceChannel::setChannelInfo(const LLSD &channelInfo)
 
     if (mState == STATE_NO_CHANNEL_INFO)
     {
-        if (mChannelInfo.isUndefined())
+        if (mChannelInfo.isUndefined() || !mChannelInfo.isMap() || mChannelInfo.size() == 0)
         {
             LLNotificationsUtil::add("VoiceChannelJoinFailed", mNotifyArgs);
             LL_WARNS("Voice") << "Received empty channel info for channel " << mSessionName << LL_ENDL;
@@ -122,7 +122,7 @@ void LLVoiceChannel::onChange(EStatusType type, const LLSD& channelInfo, bool pr
 {
     LL_DEBUGS("Voice") << "Incoming channel info: " << channelInfo << LL_ENDL;
     LL_DEBUGS("Voice") << "Current channel info: " << mChannelInfo << LL_ENDL;
-    if (mChannelInfo.isUndefined())
+    if (mChannelInfo.isUndefined() || (mChannelInfo.isMap() && mChannelInfo.size() == 0))
     {
         mChannelInfo = channelInfo;
     }
@@ -477,7 +477,7 @@ void LLVoiceChannelGroup::setChannelInfo(const LLSD& channelInfo)
 
     if (mState == STATE_NO_CHANNEL_INFO)
     {
-        if(!mChannelInfo.isUndefined())
+        if(mChannelInfo.isDefined() && mChannelInfo.isMap())
         {
             setState(STATE_READY);
 
@@ -676,9 +676,9 @@ void LLVoiceChannelProximal::activate()
         // we're connected to a non-spatial channel, so disconnect.
         LLVoiceClient::getInstance()->leaveNonSpatialChannel();
     }
+
     LLVoiceClient::getInstance()->activateSpatialChannel(true);
     LLVoiceChannel::activate();
-
 }
 
 void LLVoiceChannelProximal::onChange(EStatusType type, const LLSD& channelInfo, bool proximal)
@@ -751,7 +751,7 @@ void LLVoiceChannelProximal::deactivate()
     {
         setState(STATE_HUNG_UP);
     }
-
+    LLVoiceClient::getInstance()->removeObserver(this);
     LLVoiceClient::getInstance()->activateSpatialChannel(false);
 }
 
@@ -907,7 +907,7 @@ void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info)
     }
 
     mReceivedCall = TRUE;
-    if (!channel_info.isUndefined())
+    if (channel_info.isDefined() && channel_info.isMap())
     {
         mIncomingCallInterface = LLVoiceClient::getInstance()->getIncomingCallInterface(channel_info);
     }
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 3554933a5234da51a79d84c63a12d8f22dc8c191..1833aeb54f59574ddf20fd8e6d4809beac6354df 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -5105,25 +5105,31 @@ void LLVivoxVoiceClient::processChannels(bool process)
 
 bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo)
 {
-    if (!mProcessChannels || (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))
     {
         return false;
     }
-    if (mAudioSession)
+    // favor the next audio session, as that's the one we're bringing up.
+    sessionStatePtr_t session = mNextAudioSession;
+    if (!session)
+    {
+        session = mAudioSession;
+    }
+    if (session)
     {
         if (!channelInfo["session_handle"].asString().empty())
         {
-            return mAudioSession->mHandle == channelInfo["session_handle"].asString();
+            return session->mHandle == channelInfo["session_handle"].asString();
         }
-        return channelInfo["channel_uri"].asString() == mAudioSession->mSIPURI;
+        return channelInfo["channel_uri"].asString() == session->mSIPURI;
     }
     return false;
 }
 
 bool LLVivoxVoiceClient::compareChannels(const LLSD& channelInfo1, const LLSD& channelInfo2)
 {
-    return (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE) &&
-           (channelInfo1["voice_server_type"] == channelInfo2["voice_server_type"]) &&
+    return (!channelInfo1.has("voice_server_type") || (channelInfo1["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
+           (!channelInfo2.has("voice_server_type") || (channelInfo2["voice_server_type"] == VIVOX_VOICE_SERVER_TYPE)) &&
            (channelInfo1["channel_uri"] == channelInfo2["channel_uri"]);
 }