summaryrefslogtreecommitdiff
path: root/indra/newview/llspeakers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llspeakers.cpp')
-rwxr-xr-x[-rw-r--r--]indra/newview/llspeakers.cpp257
1 files changed, 192 insertions, 65 deletions
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 40aea05839..7867e1573c 100644..100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -31,12 +31,17 @@
#include "llagent.h"
#include "llappviewer.h"
#include "llimview.h"
+#include "llgroupmgr.h"
#include "llsdutil.h"
#include "lluicolortable.h"
+#include "llhttpclient.h"
#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llworld.h"
+extern LLControlGroup gSavedSettings;
+
const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
@@ -84,6 +89,19 @@ bool LLSpeaker::isInVoiceChannel()
return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED;
}
+LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source)
+: LLEvent(source, "Speaker update speaker event"),
+ mSpeakerID (source->mID)
+{
+}
+
+LLSD LLSpeakerUpdateSpeakerEvent::getValue()
+{
+ LLSD ret;
+ ret["id"] = mSpeakerID;
+ return ret;
+}
+
LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source)
: LLEvent(source, "Speaker add moderator event"),
mSpeakerID (source->mID),
@@ -241,16 +259,65 @@ bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_
return true;
}
+bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)
+{
+ return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end());
+}
+
+//
+// ModerationResponder
+//
+
+class ModerationResponder : public LLHTTPClient::Responder
+{
+ LOG_CLASS(ModerationResponder);
+public:
+ ModerationResponder(const LLUUID& session_id)
+ {
+ mSessionID = session_id;
+ }
+
+protected:
+ virtual void httpFailure()
+ {
+ LL_WARNS() << dumpResponse() << LL_ENDL;
+
+ if ( gIMMgr )
+ {
+ //403 == you're not a mod
+ //should be disabled if you're not a moderator
+ if ( HTTP_FORBIDDEN == getStatus() )
+ {
+ gIMMgr->showSessionEventError(
+ "mute",
+ "not_a_mod_error",
+ mSessionID);
+ }
+ else
+ {
+ gIMMgr->showSessionEventError(
+ "mute",
+ "generic_request_error",
+ mSessionID);
+ }
+ }
+ }
+
+private:
+ LLUUID mSessionID;
+};
//
// LLSpeakerMgr
//
LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
- mVoiceChannel(channelp)
-, mVoiceModerated(false)
-, mModerateModeHandledFirstTime(false)
+ mVoiceChannel(channelp),
+ mVoiceModerated(false),
+ mModerateModeHandledFirstTime(false),
+ mSpeakerListUpdated(false)
{
+ mGetListTime.reset();
static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0);
mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay);
@@ -263,7 +330,11 @@ LLSpeakerMgr::~LLSpeakerMgr()
LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
{
- if (id.isNull()) return NULL;
+ LLUUID session_id = getSessionID();
+ if (id.isNull() || (id == session_id))
+ {
+ return NULL;
+ }
LLPointer<LLSpeaker> speakerp;
if (mSpeakers.find(id) == mSpeakers.end())
@@ -272,6 +343,7 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin
speakerp->mStatus = status;
mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
mSpeakersSorted.push_back(speakerp);
+ LL_DEBUGS("Speakers") << "Added speaker " << id << LL_ENDL;
fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
}
else
@@ -290,6 +362,10 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin
speakerp->lookupName();
}
}
+ else
+ {
+ LL_WARNS("Speakers") << "Speaker " << id << " not found" << LL_ENDL;
+ }
}
mSpeakerDelayRemover->unsetActionTimer(speakerp->mID);
@@ -340,12 +416,10 @@ void LLSpeakerMgr::update(BOOL resort_ok)
// update status of all current speakers
BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
- for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
+ 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;
-
- speaker_map_t::iterator cur_speaker_it = speaker_it++;
if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
{
@@ -354,6 +428,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)
if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
{
speakerp->mModeratorMutedVoice = moderator_muted_voice;
+ LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL;
speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
}
@@ -368,6 +443,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)
{
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
speakerp->mHasSpoken = TRUE;
+ fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker");
}
speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
// interpolate between active color and full speaking color based on power of speech output
@@ -442,31 +518,107 @@ void LLSpeakerMgr::update(BOOL resort_ok)
void LLSpeakerMgr::updateSpeakerList()
{
- // are we bound to the currently active voice channel?
+ // Are we bound to the currently active voice channel?
if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()))
{
- std::set<LLUUID> participants;
- LLVoiceClient::getInstance()->getParticipantList(participants);
- // add new participants to our list of known speakers
- for (std::set<LLUUID>::iterator participant_it = participants.begin();
- participant_it != participants.end();
- ++participant_it)
+ std::set<LLUUID> participants;
+ LLVoiceClient::getInstance()->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),
LLSpeaker::STATUS_VOICE_ACTIVE,
(LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
-
-
}
}
+ else
+ {
+ // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL).
+ LLUUID session_id = getSessionID();
+ if (!session_id.isNull() && !mSpeakerListUpdated)
+ {
+ // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long.
+ // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started.
+ // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply)
+ LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
+ if (session->isGroupSessionType() && (mSpeakers.size() <= 1))
+ {
+ // For groups, we need to hit the group manager.
+ // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail.
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id);
+ F32 large_group_delay = 0.f;
+ if (gdatap)
+ {
+ //This is a viewer-side bandaid for maint-4414 it does not fix the core issue.
+ large_group_delay = (F32)(gdatap->mMemberCount / 5000);
+ }
+
+ const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout") + large_group_delay;
+
+ if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout))
+ {
+ // Request the data the first time around
+ LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id);
+ }
+ else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty())
+ {
+ // Add group members when we get the complete list (note: can take a while before we get that list)
+ LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin();
+ const S32 load_group_max_members = gSavedSettings.getS32("ChatLoadGroupMaxMembers");
+ S32 updated = 0;
+ while (member_it != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member = member_it->second;
+ LLUUID id = member_it->first;
+ // Add only members who are online and not already in the list
+ if ((member->getOnlineStatus() == "Online") && (mSpeakers.find(id) == mSpeakers.end()))
+ {
+ LLPointer<LLSpeaker> speakerp = setSpeaker(id, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ speakerp->mIsModerator = ((member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR);
+ updated++;
+ }
+ ++member_it;
+ // Limit the number of "manually updated" participants to a reasonable number to avoid severe fps drop
+ // *TODO : solve the perf issue of having several hundreds of widgets in the conversation list
+ if (updated >= load_group_max_members)
+ break;
+ }
+ mSpeakerListUpdated = true;
+ }
+ }
+ else if (mSpeakers.size() == 0)
+ {
+ // For all other session type (ad-hoc, P2P, avaline), we use the initial participants targets list
+ for (uuid_vec_t::iterator it = session->mInitialTargetIDs.begin();it!=session->mInitialTargetIDs.end();++it)
+ {
+ // Add buddies if they are on line, add any other avatar.
+ if (!LLAvatarTracker::instance().isBuddy(*it) || LLAvatarTracker::instance().isBuddyOnline(*it))
+ {
+ setSpeaker(*it, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
+ }
+ }
+ mSpeakerListUpdated = true;
+ }
+ else
+ {
+ // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server)
+ mSpeakerListUpdated = true;
+ }
+ }
+ }
+ // Always add the current agent (it has to be there...). Will do nothing if already there.
+ setSpeaker(gAgentID, "", LLSpeaker::STATUS_VOICE_ACTIVE, LLSpeaker::SPEAKER_AGENT);
}
-void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp)
+void LLSpeakerMgr::setSpeakerNotInChannel(LLPointer<LLSpeaker> speakerp)
{
- speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
- speakerp->mDotColor = INACTIVE_COLOR;
- mSpeakerDelayRemover->setActionTimer(speakerp->mID);
+ if (speakerp.notNull())
+ {
+ speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
+ speakerp->mDotColor = INACTIVE_COLOR;
+ mSpeakerDelayRemover->setActionTimer(speakerp->mID);
+ }
}
bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id)
@@ -484,6 +636,7 @@ bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id)
}
}
+ LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL;
fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove");
update(TRUE);
@@ -523,6 +676,10 @@ const LLUUID LLSpeakerMgr::getSessionID()
return mVoiceChannel->getSessionID();
}
+bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id)
+{
+ return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id);
+}
void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
{
@@ -541,6 +698,7 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
{
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
speakerp->mHasSpoken = TRUE;
+ fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker");
}
}
@@ -595,7 +753,10 @@ void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
speaker_it->second["mutes"]["text"];
// Fire event only if moderator changed
if ( is_moderator != speakerp->mIsModerator )
+ {
+ LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL;
fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
+ }
}
}
}
@@ -637,7 +798,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
if (agent_data.isMap() && agent_data.has("transition"))
{
- if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
+ if (agent_data["transition"].asString() == "LEAVE")
{
setSpeakerNotInChannel(speakerp);
}
@@ -648,7 +809,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
}
else
{
- llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
+ LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL;
}
}
@@ -665,7 +826,10 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
speakerp->mIsModerator = agent_info["is_moderator"];
// Fire event only if moderator changed
if ( is_moderator != speakerp->mIsModerator )
+ {
+ LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << LL_ENDL;
fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator");
+ }
}
if (agent_info.has("mutes"))
@@ -687,7 +851,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
std::string agent_transition = update_it->second.asString();
- if (agent_transition == "LEAVE" && speakerp.notNull())
+ if (agent_transition == "LEAVE")
{
setSpeakerNotInChannel(speakerp);
}
@@ -698,50 +862,12 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
}
else
{
- llwarns << "bad membership list update "
- << agent_transition << llendl;
+ LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL;
}
}
}
}
-class ModerationResponder : public LLHTTPClient::Responder
-{
-public:
- ModerationResponder(const LLUUID& session_id)
- {
- mSessionID = session_id;
- }
-
- virtual void error(U32 status, const std::string& reason)
- {
- llwarns << status << ": " << reason << llendl;
-
- if ( gIMMgr )
- {
- //403 == you're not a mod
- //should be disabled if you're not a moderator
- if ( 403 == status )
- {
- gIMMgr->showSessionEventError(
- "mute",
- "not_a_mod_error",
- mSessionID);
- }
- else
- {
- gIMMgr->showSessionEventError(
- "mute",
- "generic_request_error",
- mSessionID);
- }
- }
- }
-
-private:
- LLUUID mSessionID;
-};
-
void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
{
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
@@ -857,6 +983,7 @@ void LLActiveSpeakerMgr::updateSpeakerList()
// always populate from active voice channel
if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false
{
+ LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL;
fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
mSpeakers.clear();
mSpeakersSorted.clear();
@@ -916,11 +1043,11 @@ void LLLocalSpeakerMgr::updateSpeakerList()
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 (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
+ LLPointer<LLSpeaker> speakerp = speaker_it->second;
+ if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)
{
LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id);
- if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
+ if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS)
{
setSpeakerNotInChannel(speakerp);
}