[Voice Update] llfloateractivespeakers.* to llspeakers.*
Condenses the three moderation responders to one. Adds Speakers settings. Uses dedicated timer class to track speakers on the list Adds temporary getSpeakerManager() function to LLFloaterIMPanel to play the role of LLIMModel::getSpeakerManager
This commit is contained in:
@@ -34,147 +34,25 @@
|
||||
#include "llfloateractivespeakers.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llappviewer.h"
|
||||
#include "llavataractions.h"
|
||||
#include "llbutton.h"
|
||||
#include "llimpanel.h" // LLFloaterIMPanel
|
||||
#include "llimview.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llspeakers.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "llvoicechannel.h"
|
||||
#include "llworld.h"
|
||||
|
||||
// [RLVa:KB]
|
||||
#include "rlvhandler.h"
|
||||
// [/RLVa:KB]
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy muteVoiceResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy muteTextResponder_timeout;
|
||||
extern AIHTTPTimeoutPolicy moderationModeResponder_timeout;
|
||||
|
||||
using namespace LLOldEvents;
|
||||
|
||||
const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers
|
||||
const F32 RESORT_TIMEOUT = 5.f; // seconds of mouse inactivity before it's ok to sort regardless of mouse-in-view.
|
||||
const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);
|
||||
const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f);
|
||||
const F32 TYPING_ANIMATION_FPS = 2.5f;
|
||||
|
||||
LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :
|
||||
mStatus(LLSpeaker::STATUS_TEXT_ONLY),
|
||||
mLastSpokeTime(0.f),
|
||||
mSpeechVolume(0.f),
|
||||
mHasSpoken(FALSE),
|
||||
mDotColor(LLColor4::white),
|
||||
mID(id),
|
||||
mTyping(FALSE),
|
||||
mSortIndex(0),
|
||||
mType(type),
|
||||
mIsModerator(FALSE),
|
||||
mModeratorMutedVoice(FALSE),
|
||||
mModeratorMutedText(FALSE),
|
||||
mNameRequested(false)
|
||||
{
|
||||
// Make sure we also get the display name if SLIM or some other external
|
||||
// voice client is used and not whatever is provided.
|
||||
if ((name.empty() && type == SPEAKER_AGENT) || type == SPEAKER_EXTERNAL)
|
||||
{
|
||||
lookupName();
|
||||
}
|
||||
else
|
||||
{
|
||||
mDisplayName = name;
|
||||
mLegacyName = name;
|
||||
}
|
||||
mActivityTimer.reset(SPEAKER_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
void LLSpeaker::lookupName()
|
||||
{
|
||||
if(!mNameRequested)
|
||||
{
|
||||
mNameRequested = true;
|
||||
LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeaker::onNameCache(const LLAvatarName& avatar_name)
|
||||
{
|
||||
LLAvatarNameCache::getPNSName(avatar_name, mDisplayName);
|
||||
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g
|
||||
// TODO-RLVa: this seems to get called per frame which is very likely an LL bug that will eventually get fixed
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
mDisplayName = RlvStrings::getAnonym(mDisplayName);
|
||||
// [/RLVa:KB]
|
||||
|
||||
// Also set the legacy name. We will need it to initiate a new
|
||||
// IM session.
|
||||
mLegacyName = LLCacheName::cleanFullName(avatar_name.getLegacyName());
|
||||
}
|
||||
|
||||
LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source)
|
||||
: LLEvent(source, "Speaker text moderation event")
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerTextModerationEvent::getValue()
|
||||
{
|
||||
return std::string("text");
|
||||
}
|
||||
|
||||
|
||||
LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source)
|
||||
: LLEvent(source, "Speaker voice moderation event")
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerVoiceModerationEvent::getValue()
|
||||
{
|
||||
return std::string("voice");
|
||||
}
|
||||
|
||||
LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id)
|
||||
: LLEvent(source, "Speaker added/removed from speaker mgr"),
|
||||
mSpeakerID(speaker_id)
|
||||
{
|
||||
}
|
||||
|
||||
LLSD LLSpeakerListChangeEvent::getValue()
|
||||
{
|
||||
return mSpeakerID;
|
||||
}
|
||||
|
||||
// helper sort class
|
||||
struct LLSortRecentSpeakers
|
||||
{
|
||||
bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const;
|
||||
};
|
||||
|
||||
bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const
|
||||
{
|
||||
// Sort first on status
|
||||
if (lhs->mStatus != rhs->mStatus)
|
||||
{
|
||||
return (lhs->mStatus < rhs->mStatus);
|
||||
}
|
||||
|
||||
// and then on last speaking time
|
||||
if(lhs->mLastSpokeTime != rhs->mLastSpokeTime)
|
||||
{
|
||||
return (lhs->mLastSpokeTime > rhs->mLastSpokeTime);
|
||||
}
|
||||
|
||||
// and finally (only if those are both equal), on name.
|
||||
return( lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );
|
||||
}
|
||||
|
||||
//
|
||||
// LLFloaterActiveSpeakers
|
||||
@@ -610,10 +488,7 @@ void LLPanelActiveSpeakers::refreshSpeakers()
|
||||
&& selected_id != gAgent.getID()
|
||||
&& selected_speakerp.notNull()
|
||||
&& selected_speakerp->mType != LLSpeaker::SPEAKER_EXTERNAL
|
||||
// Ansariel: No, we don't want to mute Lindens with display names
|
||||
//&& !LLMuteList::getInstance()->isLinden(selected_speakerp->mDisplayName));
|
||||
&& !selected_speakerp->mLegacyName.empty()
|
||||
&& !LLMuteList::getInstance()->isLinden(selected_speakerp->mLegacyName));
|
||||
&& !LLMuteList::getInstance()->isLinden(selected_id));
|
||||
}
|
||||
mVolumeSlider->setValue(LLVoiceClient::getInstance()->getUserVolume(selected_id));
|
||||
mVolumeSlider->setEnabled(LLVoiceClient::getInstance()->voiceEnabled()
|
||||
@@ -663,11 +538,6 @@ void LLPanelActiveSpeakers::refreshSpeakers()
|
||||
mSpeakerList->getScrollInterface()->setScrollPos(scroll_pos);
|
||||
}
|
||||
|
||||
void LLPanelActiveSpeakers::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
|
||||
{
|
||||
mSpeakerMgr->setSpeaker(id, name, status, type);
|
||||
}
|
||||
|
||||
void LLPanelActiveSpeakers::setVoiceModerationCtrlMode(
|
||||
const BOOL& moderated_voice)
|
||||
{
|
||||
@@ -728,8 +598,8 @@ void LLPanelActiveSpeakers::onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_da
|
||||
|
||||
name = speakerp->mDisplayName;
|
||||
|
||||
// muting voice means we're dealing with an agent
|
||||
LLMute mute(speaker_id, name, LLMute::AGENT);
|
||||
// muting voice means we're dealing with an agent or an external voice client which won't stay muted between sessions
|
||||
LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL ? LLMute::EXTERNAL : LLMute::AGENT);
|
||||
|
||||
if (!is_muted)
|
||||
{
|
||||
@@ -790,66 +660,8 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data
|
||||
LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
|
||||
LLUICtrl* speakers_list = self->getChild<LLUICtrl>("speakers_list");
|
||||
if (!speakers_list || !gAgent.getRegion()) return;
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "mute update";
|
||||
data["session-id"] = self->mSpeakerMgr->getSessionID();
|
||||
data["params"] = LLSD::emptyMap();
|
||||
data["params"]["agent_id"] = speakers_list->getValue();
|
||||
data["params"]["mute_info"] = LLSD::emptyMap();
|
||||
// ctrl value represents ability to type, so invert
|
||||
data["params"]["mute_info"]["voice"] = !ctrl->getValue();
|
||||
|
||||
class MuteVoiceResponder : public LLHTTPClient::ResponderIgnoreBody
|
||||
{
|
||||
public:
|
||||
MuteVoiceResponder(const LLUUID& session_id)
|
||||
{
|
||||
mSessionID = session_id;
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
llwarns << status << ": " << reason << llendl;
|
||||
|
||||
if ( gIMMgr )
|
||||
{
|
||||
LLFloaterIMPanel* floaterp;
|
||||
|
||||
floaterp = gIMMgr->findFloaterBySession(mSessionID);
|
||||
|
||||
if ( floaterp )
|
||||
{
|
||||
//403 == you're not a mod
|
||||
//should be disabled if you're not a moderator
|
||||
if ( 403 == status )
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"not_a_mod_error");
|
||||
}
|
||||
else
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"generic_request_error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return muteVoiceResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "MuteVoiceResponder"; }
|
||||
|
||||
private:
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
LLHTTPClient::post(
|
||||
url,
|
||||
data,
|
||||
new MuteVoiceResponder(self->mSpeakerMgr->getSessionID()));
|
||||
if (LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(self->mSpeakerMgr))
|
||||
mgr->moderateVoiceParticipant(speakers_list->getValue(), ctrl->getValue());
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -858,66 +670,8 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data)
|
||||
LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
|
||||
LLUICtrl* speakers_list = self->getChild<LLUICtrl>("speakers_list");
|
||||
if (!speakers_list || !gAgent.getRegion()) return;
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "mute update";
|
||||
data["session-id"] = self->mSpeakerMgr->getSessionID();
|
||||
data["params"] = LLSD::emptyMap();
|
||||
data["params"]["agent_id"] = speakers_list->getValue();
|
||||
data["params"]["mute_info"] = LLSD::emptyMap();
|
||||
// ctrl value represents ability to type, so invert
|
||||
data["params"]["mute_info"]["text"] = !ctrl->getValue();
|
||||
|
||||
class MuteTextResponder : public LLHTTPClient::ResponderIgnoreBody
|
||||
{
|
||||
public:
|
||||
MuteTextResponder(const LLUUID& session_id)
|
||||
{
|
||||
mSessionID = session_id;
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
{
|
||||
llwarns << status << ": " << reason << llendl;
|
||||
|
||||
if ( gIMMgr )
|
||||
{
|
||||
LLFloaterIMPanel* floaterp;
|
||||
|
||||
floaterp = gIMMgr->findFloaterBySession(mSessionID);
|
||||
|
||||
if ( floaterp )
|
||||
{
|
||||
//403 == you're not a mod
|
||||
//should be disabled if you're not a moderator
|
||||
if ( 403 == status )
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"not_a_mod_error");
|
||||
}
|
||||
else
|
||||
{
|
||||
floaterp->showSessionEventError(
|
||||
"mute",
|
||||
"generic_request_error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return muteTextResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "MuteTextResponder"; }
|
||||
|
||||
private:
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
LLHTTPClient::post(
|
||||
url,
|
||||
data,
|
||||
new MuteTextResponder(self->mSpeakerMgr->getSessionID()));
|
||||
if (LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(self->mSpeakerMgr))
|
||||
mgr->toggleAllowTextChat(speakers_list->getValue());
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -925,533 +679,17 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da
|
||||
{
|
||||
LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data;
|
||||
if (!gAgent.getRegion()) return;
|
||||
|
||||
std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest");
|
||||
LLSD data;
|
||||
data["method"] = "session update";
|
||||
data["session-id"] = self->mSpeakerMgr->getSessionID();
|
||||
data["params"] = LLSD::emptyMap();
|
||||
|
||||
data["params"]["update_info"] = LLSD::emptyMap();
|
||||
|
||||
data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap();
|
||||
if (ctrl->getValue().asString() == "unmoderated")
|
||||
// Singu Note: moderateVoiceAllParticipants ends up flipping the boolean passed to it before the actual post
|
||||
if (LLIMSpeakerMgr* speaker_manager = dynamic_cast<LLIMSpeakerMgr*>(self->mSpeakerMgr))
|
||||
{
|
||||
data["params"]["update_info"]["moderated_mode"]["voice"] = false;
|
||||
}
|
||||
else if (ctrl->getValue().asString() == "moderated")
|
||||
{
|
||||
data["params"]["update_info"]["moderated_mode"]["voice"] = true;
|
||||
}
|
||||
|
||||
struct ModerationModeResponder : public LLHTTPClient::ResponderIgnoreBody
|
||||
{
|
||||
/*virtual*/ void error(U32 status, const std::string& reason)
|
||||
if (ctrl->getValue().asString() == "unmoderated")
|
||||
{
|
||||
llwarns << status << ": " << reason << llendl;
|
||||
speaker_manager->moderateVoiceAllParticipants(true);
|
||||
}
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationModeResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "ModerationModeResponder"; }
|
||||
};
|
||||
|
||||
LLHTTPClient::post(url, data, new ModerationModeResponder());
|
||||
}
|
||||
|
||||
//
|
||||
// LLSpeakerMgr
|
||||
//
|
||||
|
||||
LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :
|
||||
mVoiceChannel(channelp)
|
||||
{
|
||||
}
|
||||
|
||||
LLSpeakerMgr::~LLSpeakerMgr()
|
||||
{
|
||||
}
|
||||
|
||||
LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type)
|
||||
{
|
||||
if (id.isNull()) return NULL;
|
||||
|
||||
LLPointer<LLSpeaker> speakerp;
|
||||
if (mSpeakers.find(id) == mSpeakers.end())
|
||||
{
|
||||
speakerp = new LLSpeaker(id, name, type);
|
||||
speakerp->mStatus = status;
|
||||
mSpeakers.insert(std::make_pair(speakerp->mID, speakerp));
|
||||
mSpeakersSorted.push_back(speakerp);
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add");
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp = findSpeaker(id);
|
||||
if (speakerp.notNull())
|
||||
else if (ctrl->getValue().asString() == "moderated")
|
||||
{
|
||||
// keep highest priority status (lowest value) instead of overriding current value
|
||||
speakerp->mStatus = llmin(speakerp->mStatus, status);
|
||||
speakerp->mActivityTimer.reset(SPEAKER_TIMEOUT);
|
||||
// RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id
|
||||
// we need to override speakers that we think are objects when we find out they are really
|
||||
// residents
|
||||
if (type == LLSpeaker::SPEAKER_AGENT)
|
||||
{
|
||||
speakerp->mType = LLSpeaker::SPEAKER_AGENT;
|
||||
speakerp->lookupName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return speakerp;
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::update(BOOL resort_ok)
|
||||
{
|
||||
if (!LLVoiceClient::instanceExists())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor");
|
||||
LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor");
|
||||
|
||||
if(resort_ok) // only allow list changes when user is not interacting with it
|
||||
{
|
||||
updateSpeakerList();
|
||||
}
|
||||
|
||||
// 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();)
|
||||
{
|
||||
LLUUID speaker_id = speaker_it->first;
|
||||
LLSpeaker* speakerp = speaker_it->second;
|
||||
|
||||
speaker_it++;
|
||||
|
||||
if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
|
||||
{
|
||||
speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id);
|
||||
BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id);
|
||||
if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
|
||||
{
|
||||
speakerp->mModeratorMutedVoice = moderator_muted_voice;
|
||||
speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
|
||||
}
|
||||
|
||||
if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_MUTED;
|
||||
}
|
||||
else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id))
|
||||
{
|
||||
// reset inactivity expiration
|
||||
if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
|
||||
{
|
||||
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
|
||||
speakerp->mHasSpoken = TRUE;
|
||||
}
|
||||
speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
|
||||
// interpolate between active color and full speaking color based on power of speech output
|
||||
speakerp->mDotColor = speaking_color;
|
||||
if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
|
||||
{
|
||||
speakerp->mDotColor = overdriven_color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp->mSpeechVolume = 0.f;
|
||||
speakerp->mDotColor = ACTIVE_COLOR;
|
||||
|
||||
if (speakerp->mHasSpoken)
|
||||
{
|
||||
// have spoken once, not currently speaking
|
||||
speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default state for being in voice channel
|
||||
speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// speaker no longer registered in voice channel, demote to text only
|
||||
else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
|
||||
{
|
||||
if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
|
||||
{
|
||||
// external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
|
||||
speakerp->mSpeechVolume = 0.f;
|
||||
speakerp->mDotColor = ACTIVE_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(resort_ok) // only allow list changes when user is not interacting with it
|
||||
{
|
||||
// sort by status then time last spoken
|
||||
std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
|
||||
}
|
||||
|
||||
// for recent speakers who are not currently speaking, show "recent" color dot for most recent
|
||||
// fading to "active" color
|
||||
|
||||
S32 recent_speaker_count = 0;
|
||||
S32 sort_index = 0;
|
||||
speaker_list_t::iterator sorted_speaker_it;
|
||||
for(sorted_speaker_it = mSpeakersSorted.begin();
|
||||
sorted_speaker_it != mSpeakersSorted.end(); )
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
|
||||
|
||||
// color code recent speakers who are not currently speaking
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
|
||||
{
|
||||
speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
|
||||
recent_speaker_count++;
|
||||
}
|
||||
|
||||
// stuff sort ordinal into speaker so the ui can sort by this value
|
||||
speakerp->mSortIndex = sort_index++;
|
||||
|
||||
// remove speakers that have been gone too long
|
||||
if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired())
|
||||
{
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove");
|
||||
|
||||
mSpeakers.erase(speakerp->mID);
|
||||
sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++sorted_speaker_it;
|
||||
speaker_manager->moderateVoiceAllParticipants(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
setSpeaker(*participant_it,
|
||||
LLVoiceClient::getInstance()->getDisplayName(*participant_it),
|
||||
LLSpeaker::STATUS_VOICE_ACTIVE,
|
||||
(LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)
|
||||
{
|
||||
//In some conditions map causes crash if it is empty(Windows only), adding check (EK)
|
||||
if (mSpeakers.size() == 0)
|
||||
return NULL;
|
||||
speaker_map_t::iterator found_it = mSpeakers.find(speaker_id);
|
||||
if (found_it == mSpeakers.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return found_it->second;
|
||||
}
|
||||
|
||||
void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text)
|
||||
{
|
||||
speaker_list->clear();
|
||||
for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = speaker_it->second;
|
||||
// what about text only muted or inactive?
|
||||
if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY)
|
||||
{
|
||||
speaker_list->push_back(speakerp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LLUUID LLSpeakerMgr::getSessionID()
|
||||
{
|
||||
return mVoiceChannel->getSessionID();
|
||||
}
|
||||
|
||||
|
||||
void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
speakerp->mTyping = typing;
|
||||
}
|
||||
}
|
||||
|
||||
// speaker has chatted via either text or voice
|
||||
void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id)
|
||||
{
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
|
||||
if (speakerp.notNull())
|
||||
{
|
||||
speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
|
||||
speakerp->mHasSpoken = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLSpeakerMgr::isVoiceActive()
|
||||
{
|
||||
// mVoiceChannel = NULL means current voice channel, whatever it is
|
||||
return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLIMSpeakerMgr
|
||||
//
|
||||
LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel)
|
||||
{
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// don't do normal updates which are pulled from voice channel
|
||||
// rely on user list reported by sim
|
||||
|
||||
// We need to do this to allow PSTN callers into group chats to show in the list.
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers)
|
||||
{
|
||||
if ( !speakers.isMap() ) return;
|
||||
|
||||
if ( speakers.has("agent_info") && speakers["agent_info"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator speaker_it;
|
||||
for(speaker_it = speakers["agent_info"].beginMap();
|
||||
speaker_it != speakers["agent_info"].endMap();
|
||||
++speaker_it)
|
||||
{
|
||||
LLUUID agent_id(speaker_it->first);
|
||||
|
||||
LLPointer<LLSpeaker> speakerp = setSpeaker(
|
||||
agent_id,
|
||||
LLStringUtil::null,
|
||||
LLSpeaker::STATUS_TEXT_ONLY);
|
||||
|
||||
if ( speaker_it->second.isMap() )
|
||||
{
|
||||
speakerp->mIsModerator = speaker_it->second["is_moderator"];
|
||||
speakerp->mModeratorMutedText =
|
||||
speaker_it->second["mutes"]["text"];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( speakers.has("agents" ) && speakers["agents"].isArray() )
|
||||
{
|
||||
//older, more decprecated way. Need here for
|
||||
//using older version of servers
|
||||
LLSD::array_const_iterator speaker_it;
|
||||
for(speaker_it = speakers["agents"].beginArray();
|
||||
speaker_it != speakers["agents"].endArray();
|
||||
++speaker_it)
|
||||
{
|
||||
const LLUUID agent_id = (*speaker_it).asUUID();
|
||||
|
||||
LLPointer<LLSpeaker> speakerp = setSpeaker(
|
||||
agent_id,
|
||||
LLStringUtil::null,
|
||||
LLSpeaker::STATUS_TEXT_ONLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
|
||||
{
|
||||
if ( !update.isMap() ) return;
|
||||
|
||||
if ( update.has("agent_updates") && update["agent_updates"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator update_it;
|
||||
for(
|
||||
update_it = update["agent_updates"].beginMap();
|
||||
update_it != update["agent_updates"].endMap();
|
||||
++update_it)
|
||||
{
|
||||
LLUUID agent_id(update_it->first);
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
|
||||
|
||||
LLSD agent_data = update_it->second;
|
||||
|
||||
if (agent_data.isMap() && agent_data.has("transition"))
|
||||
{
|
||||
if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
speakerp->mDotColor = INACTIVE_COLOR;
|
||||
speakerp->mActivityTimer.reset(SPEAKER_TIMEOUT);
|
||||
}
|
||||
else if (agent_data["transition"].asString() == "ENTER")
|
||||
{
|
||||
// add or update speaker
|
||||
speakerp = setSpeaker(agent_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
if (speakerp.isNull()) continue;
|
||||
|
||||
// should have a valid speaker from this point on
|
||||
if (agent_data.isMap() && agent_data.has("info"))
|
||||
{
|
||||
LLSD agent_info = agent_data["info"];
|
||||
|
||||
if (agent_info.has("is_moderator"))
|
||||
{
|
||||
speakerp->mIsModerator = agent_info["is_moderator"];
|
||||
}
|
||||
|
||||
if (agent_info.has("mutes"))
|
||||
{
|
||||
speakerp->mModeratorMutedText = agent_info["mutes"]["text"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( update.has("updates") && update["updates"].isMap() )
|
||||
{
|
||||
LLSD::map_const_iterator update_it;
|
||||
for (
|
||||
update_it = update["updates"].beginMap();
|
||||
update_it != update["updates"].endMap();
|
||||
++update_it)
|
||||
{
|
||||
LLUUID agent_id(update_it->first);
|
||||
LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id);
|
||||
|
||||
std::string agent_transition = update_it->second.asString();
|
||||
if (agent_transition == "LEAVE" && speakerp.notNull())
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
speakerp->mDotColor = INACTIVE_COLOR;
|
||||
speakerp->mActivityTimer.reset(SPEAKER_TIMEOUT);
|
||||
}
|
||||
else if ( agent_transition == "ENTER")
|
||||
{
|
||||
// add or update speaker
|
||||
speakerp = setSpeaker(agent_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "bad membership list update "
|
||||
<< agent_transition << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLActiveSpeakerMgr
|
||||
//
|
||||
|
||||
LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void LLActiveSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// point to whatever the current voice channel is
|
||||
mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
|
||||
// always populate from active voice channel
|
||||
if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel)
|
||||
{
|
||||
fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");
|
||||
mSpeakers.clear();
|
||||
mSpeakersSorted.clear();
|
||||
mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();
|
||||
}
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
// clean up text only speakers
|
||||
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)
|
||||
{
|
||||
// automatically flag text only speakers for removal
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// LLLocalSpeakerMgr
|
||||
//
|
||||
|
||||
LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance())
|
||||
{
|
||||
}
|
||||
|
||||
LLLocalSpeakerMgr::~LLLocalSpeakerMgr ()
|
||||
{
|
||||
}
|
||||
|
||||
void LLLocalSpeakerMgr::updateSpeakerList()
|
||||
{
|
||||
// pull speakers from voice channel
|
||||
LLSpeakerMgr::updateSpeakerList();
|
||||
|
||||
if (gDisconnected)//the world is cleared.
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
// pick up non-voice speakers in chat range
|
||||
std::vector<LLUUID> avatar_ids;
|
||||
std::vector<LLVector3d> positions;
|
||||
LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS);
|
||||
for(U32 i=0; i<avatar_ids.size(); i++)
|
||||
{
|
||||
setSpeaker(avatar_ids[i]);
|
||||
}
|
||||
|
||||
// check if text only speakers have moved out of chat range
|
||||
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)
|
||||
{
|
||||
LLVOAvatar* avatarp = gObjectList.findAvatar(speaker_id);
|
||||
if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS)
|
||||
{
|
||||
speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
|
||||
speakerp->mDotColor = INACTIVE_COLOR;
|
||||
speakerp->mActivityTimer.reset(SPEAKER_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user