diff options
Diffstat (limited to 'indra/newview/llcallfloater.cpp')
-rw-r--r-- | indra/newview/llcallfloater.cpp | 259 |
1 files changed, 179 insertions, 80 deletions
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index fe4f0c5525..1b4c274bfb 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -40,6 +40,7 @@ #include "llagent.h" #include "llagentdata.h" // for gAgentID +#include "llavatariconctrl.h" #include "llavatarlist.h" #include "llbottomtray.h" #include "llimfloater.h" @@ -48,6 +49,7 @@ #include "llspeakers.h" #include "lltransientfloatermgr.h" +static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids); class LLNonAvatarCaller : public LLAvatarListItem { @@ -66,6 +68,8 @@ public: showLastInteractionTime(false); setShowProfileBtn(false); setShowInfoBtn(false); + mAvatarIcon->setValue("Avaline_Icon"); + mAvatarIcon->setToolTip(std::string("")); } return rv; } @@ -79,10 +83,26 @@ static void* create_non_avatar_caller(void*) return new LLNonAvatarCaller; } +LLCallFloater::LLAvatarListItemRemoveTimer::LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id) +: LLEventTimer(period) +, mRemoveCallback(remove_cb) +, mSpeakerId(speaker_id) +{ +} + +BOOL LLCallFloater::LLAvatarListItemRemoveTimer::tick() +{ + if (mRemoveCallback) + { + mRemoveCallback(mSpeakerId); + } + return TRUE; +} + LLCallFloater::LLCallFloater(const LLSD& key) : LLDockableFloater(NULL, false, key) , mSpeakerManager(NULL) -, mPaticipants(NULL) +, mParticipants(NULL) , mAvatarList(NULL) , mNonAvatarCaller(NULL) , mVoiceType(VC_LOCAL_CHAT) @@ -90,7 +110,11 @@ LLCallFloater::LLCallFloater(const LLSD& key) , mSpeakingIndicator(NULL) , mIsModeratorMutedVoice(false) , mInitParticipantsVoiceState(false) +, mVoiceLeftRemoveDelay(10) { + static LLUICachedControl<S32> voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10); + mVoiceLeftRemoveDelay = voice_left_remove_delay; + mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL); LLVoiceClient::getInstance()->addObserver(this); LLTransientFloaterMgr::getInstance()->addControlView(this); @@ -98,8 +122,10 @@ LLCallFloater::LLCallFloater(const LLSD& key) LLCallFloater::~LLCallFloater() { - delete mPaticipants; - mPaticipants = NULL; + resetVoiceRemoveTimers(); + + delete mParticipants; + mParticipants = NULL; mAvatarListRefreshConnection.disconnect(); @@ -149,7 +175,11 @@ void LLCallFloater::draw() // It should be done only when she joins or leaves voice chat. // But seems that LLVoiceClientParticipantObserver is not enough to satisfy this requirement. // *TODO: mantipov: remove from draw() - onChange(); + + // NOTE: it looks like calling onChange() here is not necessary, + // but sometime it is not called properly from the observable object. + // Seems this is a problem somewhere in Voice Client (LLVoiceClient::participantAddedEvent) +// onChange(); bool is_moderator_muted = gVoiceClient->getIsModeratorMuted(gAgentID); @@ -159,8 +189,8 @@ void LLCallFloater::draw() } // Need to resort the participant list if it's in sort by recent speaker order. - if (mPaticipants) - mPaticipants->updateRecentSpeakersOrder(); + if (mParticipants) + mParticipants->updateRecentSpeakersOrder(); LLDockableFloater::draw(); } @@ -168,9 +198,17 @@ void LLCallFloater::draw() // virtual void LLCallFloater::onChange() { - if (NULL == mPaticipants) return; + if (NULL == mParticipants) return; updateParticipantsVoiceState(); + + // Add newly joined participants. + std::vector<LLUUID> speakers_uuids; + get_voice_participants_uuids(speakers_uuids); + for (std::vector<LLUUID>::const_iterator it = speakers_uuids.begin(); it != speakers_uuids.end(); it++) + { + mParticipants->addAvatarIDExceptAgent(*it); + } } @@ -251,7 +289,7 @@ void LLCallFloater::updateSession() bool is_local_chat = mVoiceType == VC_LOCAL_CHAT; childSetVisible("leave_call_btn", !is_local_chat); - refreshPartisipantList(); + refreshParticipantList(); updateAgentModeratorState(); //show floater for voice calls @@ -266,10 +304,17 @@ void LLCallFloater::updateSession() } } -void LLCallFloater::refreshPartisipantList() +void LLCallFloater::refreshParticipantList() { - delete mPaticipants; - mPaticipants = NULL; + // lets forget states from the previous session + // for timers... + resetVoiceRemoveTimers(); + + // ...and for speaker state + mSpeakerStateMap.clear(); + + delete mParticipants; + mParticipants = NULL; mAvatarList->clear(); bool non_avatar_caller = false; @@ -289,7 +334,8 @@ void LLCallFloater::refreshPartisipantList() if (!non_avatar_caller) { - mPaticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT); + mParticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT); + mParticipants->setValidateSpeakerCallback(boost::bind(&LLCallFloater::validateSpeaker, this, _1)); if (LLLocalSpeakerMgr::getInstance() == mSpeakerManager) { @@ -414,7 +460,7 @@ void LLCallFloater::updateAgentModeratorState() mAgentPanel->childSetValue("user_text", name); } -void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids) +static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids) { // Get a list of participants from VoiceClient LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList(); @@ -482,28 +528,10 @@ void LLCallFloater::updateParticipantsVoiceState() std::vector<LLUUID> speakers_list; // Get a list of participants from VoiceClient - LLVoiceClient::participantMap *map = gVoiceClient->getParticipantList(); - if (!map) return; - - for (LLVoiceClient::participantMap::const_iterator iter = map->begin(); - iter != map->end(); ++iter) - { - LLUUID id = (*iter).second->mAvatarID; -// if ( id != gAgent.getID() ) - { - speakers_list.push_back(id); -/* - LLAvatarListItem* item = dynamic_cast<LLAvatarListItem*> (mAvatarList->getItemByValue(id)); - if (item) - { - setState(item, STATE_JOINED); - } -*/ - - } - } + std::vector<LLUUID> speakers_uuids; + get_voice_participants_uuids(speakers_uuids); - // Updating the status for each participant. + // Updating the status for each participant already in list. std::vector<LLPanel*> items; mAvatarList->getItems(items); std::vector<LLPanel*>::const_iterator @@ -518,14 +546,14 @@ void LLCallFloater::updateParticipantsVoiceState() const LLUUID participant_id = item->getAvatarId(); bool found = false; - std::vector<LLUUID>::iterator speakers_iter = std::find(speakers_list.begin(), speakers_list.end(), participant_id); + std::vector<LLUUID>::iterator speakers_iter = std::find(speakers_uuids.begin(), speakers_uuids.end(), participant_id); lldebugs << "processing speaker: " << item->getAvatarName() << ", " << item->getAvatarId() << llendl; // If an avatarID assigned to a panel is found in a speakers list // obtained from VoiceClient we assign the JOINED status to the owner // of this avatarID. - if (speakers_iter != speakers_list.end()) + if (speakers_iter != speakers_uuids.end()) { setState(item, STATE_JOINED); @@ -534,92 +562,163 @@ void LLCallFloater::updateParticipantsVoiceState() continue; speaker->mHasLeftCurrentCall = FALSE; - speakers_list.erase(speakers_iter); + speakers_uuids.erase(speakers_iter); found = true; } - // If an avatarID is not found in a speakers list from VoiceClient and - // a panel with this ID has a JOINED status this means that this person - // HAS LEFT the call. if (!found) { + // If an avatarID is not found in a speakers list from VoiceClient and + // a panel with this ID has a JOINED status this means that this person + // HAS LEFT the call. if ((getState(participant_id) == STATE_JOINED)) { - setState(item, STATE_LEFT); + if (mVoiceType == VC_LOCAL_CHAT) + { + // Don't display avatars that aren't in our nearby chat range anymore as "left". Remove them immediately. + removeVoiceLeftParticipant(participant_id); + } + else + { + setState(item, STATE_LEFT); - LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId()); - if (speaker.isNull()) - continue; + LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId()); + if (speaker.isNull()) + { + continue; + } - speaker->mHasLeftCurrentCall = TRUE; + speaker->mHasLeftCurrentCall = TRUE; + } } + // If an avatarID is not found in a speakers list from VoiceClient and + // a panel with this ID has a LEFT status this means that this person + // HAS ENTERED session but it is not in voice chat yet. So, set INVITED status else if ((getState(participant_id) != STATE_LEFT)) { setState(item, STATE_INVITED); } - -/* - // If there is already a started timer for the current panel don't do anything. - bool no_timer_for_current_panel = true; - if (mTimersMap.size() > 0) - { - timers_map::iterator found_it = mTimersMap.find(participant_id); - if (found_it != mTimersMap.end()) - { - no_timer_for_current_panel = false; - } - } - - if (no_timer_for_current_panel) + else { - // Starting a timer to remove an avatar row panel after timeout - // *TODO Make the timeout period adjustable - mTimersMap.insert(timer_pair(participant_id, new LLAvatarRowRemoveTimer(this->getHandle(), 10, participant_id))); + llwarns << "Unsupported (" << getState(participant_id) << ") state: " << item->getAvatarName() << llendl; } -*/ } } - } void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state) { - setState(item->getAvatarId(), state); + // *HACK: mantipov: sometimes such situation is possible while switching to voice channel: +/* + - voice channel is switched to the one user is joining + - participant list is initialized with voice states: agent is in voice + - than such log messages were found (with agent UUID) + - LLVivoxProtocolParser::process_impl: parsing: <Response requestId="22" action="Session.MediaDisconnect.1"><ReturnCode>0</ReturnCode><Results><StatusCode>0</StatusCode><StatusString /></Results><InputXml><Request requestId="22" action="Session.MediaDisconnect.1"><SessionGroupHandle>9</SessionGroupHandle><SessionHandle>12</SessionHandle><Media>Audio</Media></Request></InputXml></Response> + - LLVoiceClient::sessionState::removeParticipant: participant "sip:x2pwNkMbpR_mK4rtB_awASA==@bhr.vivox.com" (da9c0d90-c6e9-47f9-8ae2-bb41fdac0048) removed. + - and than while updating participants voice states agent is marked as HAS LEFT + - next updating of LLVoiceClient state makes agent JOINED + So, lets skip HAS LEFT state for agent's avatar +*/ + if (STATE_LEFT == state && item->getAvatarId() == gAgentID) return; - LLStyle::Params speaker_style; - LLFontDescriptor new_desc(speaker_style.font()->getFontDesc()); + setState(item->getAvatarId(), state); switch (state) { case STATE_INVITED: -// status_str = "INVITED"; // *TODO: localize - new_desc.setStyle(LLFontGL::NORMAL); + item->setStyle(LLAvatarListItem::IS_VOICE_INVITED); break; case STATE_JOINED: -// status_str = "JOINED"; // *TODO: localize - new_desc.setStyle(LLFontGL::NORMAL); + removeVoiceRemoveTimer(item->getAvatarId()); + item->setStyle(LLAvatarListItem::IS_VOICE_JOINED); break; case STATE_LEFT: { - // status_str = "HAS LEFT CALL"; // *TODO: localize - new_desc.setStyle(LLFontGL::ITALIC); - + setVoiceRemoveTimer(item->getAvatarId()); + item->setStyle(LLAvatarListItem::IS_VOICE_LEFT); } break; default: llwarns << "Unrecognized avatar panel state (" << state << ")" << llendl; break; } +} + +void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id) +{ + + // If there is already a started timer for the current panel don't do anything. + bool no_timer_for_current_panel = true; + if (mVoiceLeftTimersMap.size() > 0) + { + timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); + if (found_it != mVoiceLeftTimersMap.end()) + { + no_timer_for_current_panel = false; + } + } + + if (no_timer_for_current_panel) + { + // Starting a timer to remove an avatar row panel after timeout + mVoiceLeftTimersMap.insert(timer_pair(voice_speaker_id, + new LLAvatarListItemRemoveTimer(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), mVoiceLeftRemoveDelay, voice_speaker_id))); + } +} + +void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id) +{ + if (mVoiceLeftTimersMap.size() > 0) + { + mVoiceLeftTimersMap.erase(mVoiceLeftTimersMap.find(voice_speaker_id)); + } - LLFontGL* new_font = LLFontGL::getFont(new_desc); - speaker_style.font = new_font; - item->setStyle(speaker_style); + LLAvatarList::uuid_vector_t& speaker_uuids = mAvatarList->getIDs(); + LLAvatarList::uuid_vector_t::iterator pos = std::find(speaker_uuids.begin(), speaker_uuids.end(), voice_speaker_id); + if(pos != speaker_uuids.end()) + { + speaker_uuids.erase(pos); + mAvatarList->setDirty(); + } +} -// if () + +void LLCallFloater::resetVoiceRemoveTimers() +{ + if (mVoiceLeftTimersMap.size() > 0) { - // found speaker is in voice, mark him as online - item->setOnline(STATE_JOINED == state); + for (timers_map::iterator iter = mVoiceLeftTimersMap.begin(); + iter != mVoiceLeftTimersMap.end(); ++iter) + { + delete iter->second; + } } + mVoiceLeftTimersMap.clear(); +} + +void LLCallFloater::removeVoiceRemoveTimer(const LLUUID& voice_speaker_id) +{ + // Remove the timer if it has been already started + if (mVoiceLeftTimersMap.size() > 0) + { + timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id); + if (found_it != mVoiceLeftTimersMap.end()) + { + delete found_it->second; + mVoiceLeftTimersMap.erase(found_it); + } + } +} + +bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id) +{ + if (mVoiceType != VC_LOCAL_CHAT) + return true; + + // A nearby chat speaker is considered valid it it's known to LLVoiceClient (i.e. has enabled voice). + std::vector<LLUUID> speakers; + get_voice_participants_uuids(speakers); + return std::find(speakers.begin(), speakers.end(), speaker_id) != speakers.end(); } //EOF |