diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index ae1c28c7ab244155998d4570576d10a5a3ea7a43..8d03f9e68654c183ab250917f01201bd4ae5dcb1 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -247,6 +247,10 @@ void LLPanelGroupControlPanel::draw()
 	//Remove event does not raised until speakerp->mActivityTimer.hasExpired() is false, see LLSpeakerManager::update()
 	//so we need update it to raise needed event
 	mSpeakerManager->update(true);
+	// Need to refresh participants to display ones not in voice as disabled and 
+	// resort the avatar list if it's in sort by recent speaker order.
+	if (mParticipantList)
+		mParticipantList->refreshVoiceState();
 	LLPanelChatControlPanel::draw();
 }
 
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index e8aa1e983190f7bd8c7b29be8bbb46ecea0acd57..8fb4063ea7d502fa69a608d65fff25763a243e73 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -39,7 +39,6 @@
 #include "llimview.h"
 
 #include "llparticipantlist.h"
-#include "llavatarlist.h"
 #include "llspeakers.h"
 #include "llviewermenu.h"
 #include "llvoiceclient.h"
@@ -204,6 +203,11 @@ void LLParticipantList::setSortOrder(EParticipantSortOrder order)
 	}
 }
 
+LLParticipantList::EParticipantSortOrder LLParticipantList::getSortOrder()
+{
+	return mSortOrder;
+}
+
 void LLParticipantList::refreshVoiceState()
 {
 	LLSpeakerMgr::speaker_list_t speakers;
@@ -223,6 +227,12 @@ void LLParticipantList::refreshVoiceState()
 			item->setOnline(!is_in_voice);
 		}
 	}
+	if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder())
+	{
+		// Resort avatar list
+		mAvatarList->setDirty(true);
+		sort();
+	}
 }
 
 bool LLParticipantList::onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)
@@ -312,7 +322,6 @@ void LLParticipantList::sort()
 	if ( !mAvatarList )
 		return;
 
-	// TODO: Implement more sorting orders after specs updating (EM)
 	switch ( mSortOrder ) {
 	case E_SORT_BY_NAME :
 		// if mExcludeAgent == true , then no need to keep agent on top of the list
@@ -326,6 +335,12 @@ void LLParticipantList::sort()
 			mAvatarList->sort();
 		}
 		break;
+	case E_SORT_BY_RECENT_SPEAKERS:
+		if (mSortByRecentSpeakers.isNull())
+			mSortByRecentSpeakers = new LLAvatarItemRecentSpeakerComparator(*this);
+		mAvatarList->setComparator(mSortByRecentSpeakers.get());
+		mAvatarList->sort();
+		break;
 	default :
 		llwarns << "Unrecognized sort order for " << mAvatarList->getName() << llendl;
 		return;
@@ -402,6 +417,7 @@ LLContextMenu* LLParticipantList::LLParticipantListMenu::createMenu()
 	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
 	
+	registrar.add("ParticipantList.Sort", boost::bind(&LLParticipantList::LLParticipantListMenu::sortParticipantList, this, _2));
 	registrar.add("ParticipantList.ToggleAllowTextChat", boost::bind(&LLParticipantList::LLParticipantListMenu::toggleAllowTextChat, this, _2));
 	registrar.add("ParticipantList.ToggleMuteText", boost::bind(&LLParticipantList::LLParticipantListMenu::toggleMuteText, this, _2));
 
@@ -447,6 +463,24 @@ void LLParticipantList::LLParticipantListMenu::show(LLView* spawning_view, const
 		LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteSelected", false);
 		LLMenuGL::sMenuContainer->childSetVisible("ModerateVoiceUnMuteOthers", false);
 	}
+
+	// Don't show sort options for P2P chat
+	bool is_sort_visible = (mParent.mAvatarList && mParent.mAvatarList->size() > 1);
+	LLMenuGL::sMenuContainer->childSetVisible("SortByName", is_sort_visible);
+	LLMenuGL::sMenuContainer->childSetVisible("SortByRecentSpeakers", is_sort_visible);
+}
+
+void LLParticipantList::LLParticipantListMenu::sortParticipantList(const LLSD& userdata)
+{
+	std::string param = userdata.asString();
+	if ("sort_by_name" == param)
+	{
+		mParent.setSortOrder(E_SORT_BY_NAME);
+	}
+	else if ("sort_by_recent_speakers" == param)
+	{
+		mParent.setSortOrder(E_SORT_BY_RECENT_SPEAKERS);
+	}
 }
 
 void LLParticipantList::LLParticipantListMenu::toggleAllowTextChat(const LLSD& userdata)
@@ -616,8 +650,45 @@ bool LLParticipantList::LLParticipantListMenu::checkContextMenuItem(const LLSD&
 	{
 		return LLMuteList::getInstance()->isMuted(id, LLMute::flagVoiceChat);
 	}
+	else if(item == "is_sorted_by_name")
+	{
+		return E_SORT_BY_NAME == mParent.mSortOrder;
+	}
+	else if(item == "is_sorted_by_recent_speakers")
+	{
+		return E_SORT_BY_RECENT_SPEAKERS == mParent.mSortOrder;
+	}
 
 	return false;
 }
 
+bool LLParticipantList::LLAvatarItemRecentSpeakerComparator::doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const
+{
+	if (mParent.mSpeakerMgr)
+	{
+		LLPointer<LLSpeaker> lhs = mParent.mSpeakerMgr->findSpeaker(avatar_item1->getAvatarId());
+		LLPointer<LLSpeaker> rhs = mParent.mSpeakerMgr->findSpeaker(avatar_item2->getAvatarId());
+		if ( lhs.notNull() && rhs.notNull() )
+		{
+			// Compare by last speaking time
+			if( lhs->mLastSpokeTime != rhs->mLastSpokeTime )
+				return ( lhs->mLastSpokeTime > rhs->mLastSpokeTime );
+			else if ( lhs->mSortIndex != rhs->mSortIndex )
+				return ( lhs->mSortIndex < rhs->mSortIndex );
+		}
+		else if ( lhs.notNull() )
+		{
+			// True if only avatar_item1 speaker info available
+			return true;
+		}
+		else if ( rhs.notNull() )
+		{
+			// False if only avatar_item2 speaker info available
+			return false;
+		}
+	}
+	// By default compare by name.
+	return LLAvatarItemNameComparator::doCompare(avatar_item1, avatar_item2);
+}
+
 //EOF
diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h
index b85d4c9bc43c71cbc6508cc9a8b83cba75d35ec4..21eda86edd32332d1a357c4e3e9344b205ac4871 100644
--- a/indra/newview/llparticipantlist.h
+++ b/indra/newview/llparticipantlist.h
@@ -34,6 +34,7 @@
 #include "llevent.h"
 #include "llpanelpeoplemenus.h"
 #include "llimview.h"
+#include "llavatarlist.h" // for LLAvatarItemRecentSpeakerComparator
 
 class LLSpeakerMgr;
 class LLAvatarList;
@@ -49,12 +50,14 @@ class LLParticipantList
 
 		typedef enum e_participant_sort_oder {
 			E_SORT_BY_NAME = 0,
+			E_SORT_BY_RECENT_SPEAKERS = 1,
 		} EParticipantSortOrder;
 
 		/**
 		 * Set and sort Avatarlist by given order
 		 */
 		void setSortOrder(EParticipantSortOrder order = E_SORT_BY_NAME);
+		EParticipantSortOrder getSortOrder();
 
 		/**
 		 * Refreshes participants to display ones not in voice as disabled.
@@ -139,6 +142,7 @@ class LLParticipantList
 			bool enableContextMenuItem(const LLSD& userdata);
 			bool checkContextMenuItem(const LLSD& userdata);
 
+			void sortParticipantList(const LLSD& userdata);
 			void toggleAllowTextChat(const LLSD& userdata);
 			void toggleMute(const LLSD& userdata, U32 flags);
 			void toggleMuteText(const LLSD& userdata);
@@ -195,6 +199,21 @@ class LLParticipantList
 			void moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute);
 		};
 
+		/**
+		 * Comparator for comparing avatar items by last spoken time
+		 */
+		class LLAvatarItemRecentSpeakerComparator : public LLAvatarItemNameComparator, public LLRefCount
+		{
+			LOG_CLASS(LLAvatarItemRecentSpeakerComparator);
+		  public:
+			LLAvatarItemRecentSpeakerComparator(LLParticipantList& parent):mParent(parent){};
+			virtual ~LLAvatarItemRecentSpeakerComparator() {};
+		  protected:
+			virtual bool doCompare(const LLAvatarListItem* avatar_item1, const LLAvatarListItem* avatar_item2) const;
+		  private:
+			LLParticipantList& mParent;
+		};
+
 	private:
 		void onAvatarListDoubleClicked(LLAvatarList* list);
 		void onAvatarListRefreshed(LLUICtrl* ctrl, const LLSD& param);
@@ -240,4 +259,6 @@ class LLParticipantList
 		boost::signals2::connection mAvatarListDoubleClickConnection;
 		boost::signals2::connection mAvatarListRefreshConnection;
 		boost::signals2::connection mAvatarListReturnConnection;
+
+		LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers;
 };
diff --git a/indra/newview/skins/default/xui/en/menu_participant_list.xml b/indra/newview/skins/default/xui/en/menu_participant_list.xml
index faf33bd1b16435e541a62f2fa9c1fa363bdfae5d..31263fbea8bb7e675b1ee094eb91490ba0f407de 100644
--- a/indra/newview/skins/default/xui/en/menu_participant_list.xml
+++ b/indra/newview/skins/default/xui/en/menu_participant_list.xml
@@ -2,7 +2,29 @@
 <context_menu
  layout="topleft"
  name="Participant List Context Menu">
- <menu_item_call
+    <menu_item_check
+     label="Sort by Name"
+     layout="topleft"
+     name="SortByName">
+        <menu_item_check.on_click
+         function="ParticipantList.Sort"
+         parameter="sort_by_name" />
+        <menu_item_check.on_check
+         function="ParticipantList.CheckItem"
+         parameter="is_sorted_by_name" />
+    </menu_item_check>
+    <menu_item_check
+     label="Sort by Recent Speakers"
+     layout="topleft"
+     name="SortByRecentSpeakers">
+        <menu_item_check.on_click
+         function="ParticipantList.Sort"
+         parameter="sort_by_recent_speakers" />
+        <menu_item_check.on_check
+         function="ParticipantList.CheckItem"
+         parameter="is_sorted_by_recent_speakers" />
+    </menu_item_check>
+    <menu_item_call
      label="View Profile"
      layout="topleft"
      name="View Profile">