From ab0c9c6754836cb26a520d0a9b2d7bbdd13a5f32 Mon Sep 17 00:00:00 2001
From: Andrew Dyukov <adyukov@productengine.com>
Date: Fri, 22 Jan 2010 22:16:57 +0200
Subject: [PATCH] Fixed normal bugs EXT-4450 ([BSI] call buttons enabled when
 voice is disabled) and EXT-4313 (Should not be able to start a call when
 voice is disabled). Call buttons state now reacts on voice changes in time.

- Added voiceWorking() method to LLVoiceClient to determine real availability of voice, because voiceEnabled()
doesn't take into account possible errors. Perhaps there is no need in two methods- some investigation will be
made and depending on its results they may become one non-static method. voiceWorking() uses state of voice
client(mState) to determine voice availability. Also some states which are not currently counted by voiceWorking()
as valid may be added if testing reveals problems.

- To enable/disable call buttons in time, LLVoiceClientStatusObserver is used. Its trigger uses states from its
enum only to skip updating button in some states(to avoid button blinking), but to determine button state
LLVoiceClient's voiceWorking() is used.

--HG--
branch : product-engine
---
 indra/newview/llavataractions.cpp       | 13 +-----
 indra/newview/llavataractions.h         |  4 +-
 indra/newview/llgrouplist.cpp           |  4 ++
 indra/newview/llpanelavatar.cpp         | 31 +++++++++++++-
 indra/newview/llpanelavatar.h           | 11 +++++
 indra/newview/llpanelgroup.cpp          | 33 ++++++++++-----
 indra/newview/llpanelgroup.h            |  8 +++-
 indra/newview/llpanelimcontrolpanel.cpp | 54 ++++++++++++++++---------
 indra/newview/llpanelimcontrolpanel.h   | 12 +++++-
 indra/newview/llpanelpeople.cpp         | 45 +++++++++------------
 indra/newview/llpanelpeople.h           |  9 ++++-
 indra/newview/llpanelpeoplemenus.cpp    | 15 +------
 indra/newview/llparticipantlist.cpp     |  2 +-
 indra/newview/llvoiceclient.cpp         |  5 +++
 indra/newview/llvoiceclient.h           |  2 +
 15 files changed, 159 insertions(+), 89 deletions(-)

diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 40c9bb6afab..bb14c41cec8 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -263,18 +263,9 @@ bool LLAvatarActions::isCalling(const LLUUID &id)
 }
 
 //static
-bool LLAvatarActions::canCall(const LLUUID &id)
+bool LLAvatarActions::canCall()
 {
-	// For now we do not need to check whether passed UUID is ID of agent's friend.
-	// Use common check of Voice Client state.
-	{
-		// don't need to check online/offline status because "usual resident" (resident that is not a friend)
-		// can be only ONLINE. There is no way to see "usual resident" in OFFLINE status. If we see "usual
-		// resident" it automatically means that the resident is ONLINE. So to make a call to the "usual resident"
-		// we need to check only that "our" voice is enabled.
-		return LLVoiceClient::voiceEnabled();
-	}
-
+		return LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
 }
 
 // static
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index a4504ae679b..ebfd40b796f 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -129,10 +129,10 @@ class LLAvatarActions
 	static bool isCalling(const LLUUID &id);
 
 	/**
-	 * @return true if call to the resident can be made (resident is online and voice is enabled)
+	 * @return true if call to the resident can be made
 	 */
 
-	static bool canCall(const LLUUID &id);
+	static bool canCall();
 	/**
 	 * Invite avatar to a group.
 	 */	
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index e75d35bea41..e01709aa3a0 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -48,6 +48,7 @@
 #include "lltextutil.h"
 #include "llviewercontrol.h"	// for gSavedSettings
 #include "llviewermenu.h"		// for gMenuHolder
+#include "llvoiceclient.h"
 
 static LLDefaultChildRegistry::Register<LLGroupList> r("group_list");
 S32 LLGroupListItem::sIconWidth = 0;
@@ -271,6 +272,9 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
 	if (userdata.asString() == "activate")
 		return gAgent.getGroupID() != selected_group_id;
 
+	if (userdata.asString() == "call")
+		return LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();
+
 	return real_group_selected;
 }
 
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 85e95ca1d65..564c80a492c 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -165,6 +165,8 @@ BOOL LLPanelAvatarNotes::postBuild()
 	resetControls();
 	resetData();
 
+	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+
 	return TRUE;
 }
 
@@ -337,6 +339,8 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+		if(LLVoiceClient::getInstance())
+			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
@@ -346,6 +350,17 @@ void LLPanelAvatarNotes::changed(U32 mask)
 	childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId()));
 }
 
+// virtual
+void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelAvatarNotes::setAvatarId(const LLUUID& id)
 {
 	if(id.notNull())
@@ -437,7 +452,6 @@ void LLPanelProfileTab::updateButtons()
 
 	bool enable_map_btn = is_avatar_online && gAgent.isGodlike() || is_agent_mappable(getAvatarId());
 	childSetEnabled("show_on_map_btn", enable_map_btn);
-	childSetEnabled("call", LLAvatarActions::canCall(getAvatarId()));
 }
 
 //////////////////////////////////////////////////////////////////////////
@@ -485,6 +499,8 @@ BOOL LLPanelAvatarProfile::postBuild()
 	pic = getChild<LLTextureCtrl>("real_world_pic");
 	pic->setFallbackImageName("default_profile_picture.j2c");
 
+	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+
 	resetControls();
 	resetData();
 
@@ -757,6 +773,8 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+		if(LLVoiceClient::getInstance())
+			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
@@ -766,6 +784,17 @@ void LLPanelAvatarProfile::changed(U32 mask)
 	childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId()));
 }
 
+// virtual
+void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelAvatarProfile::setAvatarId(const LLUUID& id)
 {
 	if(id.notNull())
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 22efa5dc351..1174c72d60c 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -36,6 +36,7 @@
 #include "llpanel.h"
 #include "llavatarpropertiesprocessor.h"
 #include "llcallingcard.h"
+#include "llvoiceclient.h"
 
 class LLComboBox;
 class LLLineEditor;
@@ -122,6 +123,7 @@ class LLPanelProfileTab
 class LLPanelAvatarProfile
 	: public LLPanelProfileTab
 	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelAvatarProfile();
@@ -134,6 +136,10 @@ class LLPanelAvatarProfile
 	 */
 	virtual void changed(U32 mask);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	/*virtual*/ void setAvatarId(const LLUUID& id);
 
 	/**
@@ -257,6 +263,7 @@ class LLPanelMyProfile
 class LLPanelAvatarNotes 
 	: public LLPanelProfileTab
 	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelAvatarNotes();
@@ -269,6 +276,10 @@ class LLPanelAvatarNotes
 	 */
 	virtual void changed(U32 mask);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	/*virtual*/ void onOpen(const LLSD& key);
 
 	/*virtual*/ BOOL postBuild();
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index c30ef3221d4..1d447a22d73 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -101,6 +101,8 @@ LLPanelGroup::LLPanelGroup()
 LLPanelGroup::~LLPanelGroup()
 {
 	LLGroupMgr::getInstance()->removeObserver(this);
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
 }
 
 void LLPanelGroup::onOpen(const LLSD& key)
@@ -188,6 +190,8 @@ BOOL LLPanelGroup::postBuild()
 
 	if(panel_general)
 		panel_general->setupCtrls(this);
+
+	gVoiceClient->addObserver(this);
 	
 	return TRUE;
 }
@@ -300,6 +304,17 @@ void LLPanelGroup::changed(LLGroupChange gc)
 	update(gc);
 }
 
+// virtual
+void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("btn_call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelGroup::notifyObservers()
 {
 	changed(GC_ALL);
@@ -356,6 +371,13 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
 	for(std::vector<LLPanelGroupTab* >::iterator it = mTabs.begin();it!=mTabs.end();++it)
 		(*it)->setGroupID(group_id);
 
+	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID);
+	if(gdatap)
+	{
+		childSetValue("group_name", gdatap->mName);
+		childSetToolTip("group_name",gdatap->mName);
+	}
+
 	LLButton* button_apply = findChild<LLButton>("btn_apply");
 	LLButton* button_refresh = findChild<LLButton>("btn_refresh");
 	LLButton* button_create = findChild<LLButton>("btn_create");
@@ -457,17 +479,6 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
 	}
 
 	reposButtons();
-
-	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID);
-
-	if(gdatap)
-	{
-		childSetValue("group_name", gdatap->mName);
-		childSetToolTip("group_name",gdatap->mName);
-		
-		//group data is already present, call update manually
-		update(GC_ALL);
-	}
 }
 
 bool LLPanelGroup::apply(LLPanelGroupTab* tab)
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 7ea5e67b44f..8c846956771 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -35,6 +35,7 @@
 #include "llgroupmgr.h"
 #include "llpanel.h"
 #include "lltimer.h"
+#include "llvoiceclient.h"
 
 struct LLOfferInfo;
 
@@ -47,7 +48,8 @@ class LLAgent;
 
 
 class LLPanelGroup : public LLPanel,
-					 public LLGroupMgrObserver 
+					 public LLGroupMgrObserver,
+					 public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelGroup();
@@ -64,6 +66,10 @@ class LLPanelGroup : public LLPanel,
 	// Group manager observer trigger.
 	virtual void changed(LLGroupChange gc);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	void showNotice(const std::string& subject,
 					const std::string& message,
 					const bool& has_inventory,
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index a334eb9d680..ff1e43b5268 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -64,21 +64,52 @@ void LLPanelChatControlPanel::onOpenVoiceControlsClicked()
 	LLFloaterReg::showInstance("voice_controls");
 }
 
+void LLPanelChatControlPanel::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	updateCallButton();
+}
+
 void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)
 {
 	updateButtons(new_state >= LLVoiceChannel::STATE_CALL_STARTED);
 }
 
+void LLPanelChatControlPanel::updateCallButton()
+{
+	// hide/show call button
+	bool voice_enabled = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
+
+	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
+	if (!session) return;
+
+	bool session_initialized = session->mSessionInitialized;
+	bool callback_enabled = session->mCallBackEnabled;
+
+	BOOL enable_connect = session_initialized
+		&& voice_enabled
+		&& callback_enabled;
+	childSetEnabled("call_btn", enable_connect);
+}
+
 void LLPanelChatControlPanel::updateButtons(bool is_call_started)
 {
 	childSetVisible("end_call_btn_panel", is_call_started);
 	childSetVisible("voice_ctrls_btn_panel", is_call_started);
 	childSetVisible("call_btn_panel", ! is_call_started);
+	updateCallButton();
+	
 }
 
 LLPanelChatControlPanel::~LLPanelChatControlPanel()
 {
 	mVoiceChannelStateChangeConnection.disconnect();
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
 }
 
 BOOL LLPanelChatControlPanel::postBuild()
@@ -87,26 +118,9 @@ BOOL LLPanelChatControlPanel::postBuild()
 	childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this));
 	childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this));
 
-	return TRUE;
-}
-
-void LLPanelChatControlPanel::draw()
-{
-	// hide/show start call and end call buttons
-	bool voice_enabled = LLVoiceClient::voiceEnabled();
-
-	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
-	if (!session) return;
+	gVoiceClient->addObserver(this);
 
-	bool session_initialized = session->mSessionInitialized;
-	bool callback_enabled = session->mCallBackEnabled;
-
-	BOOL enable_connect = session_initialized
-		&& voice_enabled
-		&& callback_enabled;
-	childSetEnabled("call_btn", enable_connect);
-
-	LLPanel::draw();
+	return TRUE;
 }
 
 void LLPanelChatControlPanel::setSessionId(const LLUUID& session_id)
@@ -266,6 +280,8 @@ void LLPanelGroupControlPanel::draw()
 	// Need to resort the participant list if it's in sort by recent speaker order.
 	if (mParticipantList)
 		mParticipantList->updateRecentSpeakersOrder();
+	//* TODO: find better way to properly enable call button for group and remove this call from draw()
+	updateCallButton();
 	LLPanelChatControlPanel::draw();
 }
 
diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h
index 25fdf944c92..3ab505a084d 100644
--- a/indra/newview/llpanelimcontrolpanel.h
+++ b/indra/newview/llpanelimcontrolpanel.h
@@ -39,7 +39,9 @@
 
 class LLParticipantList;
 
-class LLPanelChatControlPanel : public LLPanel
+class LLPanelChatControlPanel 
+	: public LLPanel
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelChatControlPanel() :
@@ -47,15 +49,21 @@ class LLPanelChatControlPanel : public LLPanel
 	~LLPanelChatControlPanel();
 
 	virtual BOOL postBuild();
-	virtual void draw();
 
 	void onCallButtonClicked();
 	void onEndCallButtonClicked();
 	void onOpenVoiceControlsClicked();
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	virtual void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state);
 
 	void updateButtons(bool is_call_started);
+	
+	// Enables/disables call button depending on voice availability
+	void updateCallButton();
 
 	virtual void setSessionId(const LLUUID& session_id);
 	const LLUUID& getSessionId() { return mSessionId; }
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index c14b282488c..b01cdcc832b 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -462,6 +462,9 @@ LLPanelPeople::~LLPanelPeople()
 	delete mFriendListUpdater;
 	delete mRecentListUpdater;
 
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
+
 	LLView::deleteViewByHandle(mGroupPlusMenuHandle);
 	LLView::deleteViewByHandle(mNearbyViewSortMenuHandle);
 	LLView::deleteViewByHandle(mFriendsViewSortMenuHandle);
@@ -612,6 +615,8 @@ BOOL LLPanelPeople::postBuild()
 	if(recent_view_sort)
 		mRecentViewSortMenuHandle  = recent_view_sort->getHandle();
 
+	gVoiceClient->addObserver(this);
+
 	// call this method in case some list is empty and buttons can be in inconsistent state
 	updateButtons();
 
@@ -621,6 +626,17 @@ BOOL LLPanelPeople::postBuild()
 	return TRUE;
 }
 
+// virtual
+void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+	
+	updateButtons();
+}
+
 void LLPanelPeople::updateFriendList()
 {
 	if (!mOnlineFriendList || !mAllFriendList)
@@ -775,41 +791,20 @@ void LLPanelPeople::updateButtons()
 		}
 	}
 
+	bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled();
+
 	buttonSetEnabled("teleport_btn",		friends_tab_active && item_selected && isFriendOnline(selected_uuids.front()));
 	buttonSetEnabled("view_profile_btn",	item_selected);
 	buttonSetEnabled("im_btn",				multiple_selected); // allow starting the friends conference for multiple selection
-	buttonSetEnabled("call_btn",			multiple_selected && canCall());
+	buttonSetEnabled("call_btn",			multiple_selected && enable_calls);
 	buttonSetEnabled("share_btn",			item_selected); // not implemented yet
 
 	bool none_group_selected = item_selected && selected_id.isNull();
 	buttonSetEnabled("group_info_btn", !none_group_selected);
-	buttonSetEnabled("group_call_btn", !none_group_selected);
+	buttonSetEnabled("group_call_btn", !none_group_selected && enable_calls);
 	buttonSetEnabled("chat_btn", !none_group_selected);
 }
 
-bool LLPanelPeople::canCall()
-{
-	std::vector<LLUUID> selected_uuids;
-	getCurrentItemIDs(selected_uuids);
-
-	bool result = false;
-
-	std::vector<LLUUID>::const_iterator
-		id = selected_uuids.begin(),
-		uuids_end = selected_uuids.end();
-
-	for (;id != uuids_end; ++id)
-	{
-		if (LLAvatarActions::canCall(*id))
-		{
-			result = true;
-			break;
-		}
-	}
-
-	return result;
-}
-
 std::string LLPanelPeople::getActiveTabName() const
 {
 	return mTabContainer->getCurrentPanel()->getName();
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 7580fdbeeff..6d3d4361568 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -36,13 +36,16 @@
 #include <llpanel.h>
 
 #include "llcallingcard.h" // for avatar tracker
+#include "llvoiceclient.h"
 
 class LLFilterEditor;
 class LLTabContainer;
 class LLAvatarList;
 class LLGroupList;
 
-class LLPanelPeople : public LLPanel
+class LLPanelPeople 
+	: public LLPanel
+	, public LLVoiceClientStatusObserver
 {
 	LOG_CLASS(LLPanelPeople);
 public:
@@ -52,6 +55,9 @@ class LLPanelPeople : public LLPanel
 	/*virtual*/ BOOL 	postBuild();
 	/*virtual*/ void	onOpen(const LLSD& key);
 	/*virtual*/ bool	notifyChildren(const LLSD& info);
+	// Implements LLVoiceClientStatusObserver::onChange() to enable call buttons
+	// when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
 
 	// internals
 	class Updater;
@@ -73,7 +79,6 @@ class LLPanelPeople : public LLPanel
 
 	bool					isFriendOnline(const LLUUID& id);
 	bool					isItemsFreeOfFriends(const std::vector<LLUUID>& uuids);
-	bool 					canCall();
 
 	void					updateButtons();
 	std::string				getActiveTabName() const;
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index c1c10e60220..d9651a60450 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -183,20 +183,7 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata)
 	}
 	else if (item == std::string("can_call"))
 	{
-		bool result = false;
-		std::vector<LLUUID>::const_iterator
-			id = mUUIDs.begin(),
-			uuids_end = mUUIDs.end();
-
-		for (;id != uuids_end; ++id)
-		{
-			if (LLAvatarActions::canCall(*id))
-			{
-				result = true;
-				break;
-			}
-		}
-		return result;
+		return LLAvatarActions::canCall();
 	}
 	return false;
 }
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 88b706fb6bf..c0302eee9e0 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -628,7 +628,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD&
 	}
 	else if (item == "can_call")
 	{
-		return LLVoiceClient::voiceEnabled();
+		return LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();
 	}
 
 	return true;
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index c84afa5af12..e52d6a089bd 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -5853,6 +5853,11 @@ bool LLVoiceClient::voiceEnabled()
 	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
 }
 
+bool LLVoiceClient::voiceWorking()
+{
+	return (stateLoggedIn <= mState) && (mState <= stateLeavingSession);
+}
+
 void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
 {
 	mLipSyncEnabled = enabled;
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 6231c6ba29f..8f668dff196 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -191,6 +191,8 @@ static	void updatePosition(void);
 		void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
 		void setVoiceEnabled(bool enabled);
 		static bool voiceEnabled();
+		// Checks is voice working judging from mState
+		bool voiceWorking();
 		void setUsePTT(bool usePTT);
 		void setPTTIsToggle(bool PTTIsToggle);
 		bool getPTTIsToggle();
-- 
GitLab