diff options
Diffstat (limited to 'indra/newview')
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 12 | ||||
| -rw-r--r-- | indra/newview/llpanelimcontrolpanel.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llspeakers.cpp | 152 | ||||
| -rw-r--r-- | indra/newview/llspeakers.h | 94 | 
4 files changed, 229 insertions, 32 deletions
| diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index a4fc095727..c29a3a0035 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10070,6 +10070,18 @@        <key>Value</key>        <integer>1</integer>      </map> +    <key>SpeakerParticipantRemoveDelay</key> +    <map> +      <key>Comment</key> +      <string>Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>10.0</real> +    </map> +      <key>UseStartScreen</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index b1cdb4d81f..86bdee7c7d 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -264,9 +264,6 @@ LLPanelGroupControlPanel::~LLPanelGroupControlPanel()  // virtual  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 resort the participant list if it's in sort by recent speaker order.  	if (mParticipantList)  		mParticipantList->updateRecentSpeakersOrder(); diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 0dd9203c6d..9608cd1263 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -44,7 +44,6 @@  #include "llvoavatar.h"  #include "llworld.h" -const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers  const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f);  const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); @@ -73,8 +72,6 @@ LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerTy  	}  	gVoiceClient->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id)); - -	mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT);  } @@ -164,6 +161,89 @@ bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPo  	return(	lhs->mDisplayName.compare(rhs->mDisplayName) < 0 );  } +LLSpeakerActionTimer::LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id) +: LLEventTimer(action_period) +, mActionCallback(action_cb) +, mSpeakerId(speaker_id) +{ +} + +BOOL LLSpeakerActionTimer::tick() +{ +	if (mActionCallback) +	{ +		return (BOOL)mActionCallback(mSpeakerId); +	} +	return TRUE; +} + +LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay) +: mActionCallback(action_cb) +, mActionDelay(action_delay) +{ +} + +LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() +{ +	removeAllTimers(); +} + +void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) +{ +	bool not_found = true; +	if (mActionTimersMap.size() > 0) +	{ +		not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); +	} + +	// If there is already a started timer for the passed UUID don't do anything. +	if (not_found) +	{ +		// Starting a timer to remove an participant after delay is completed +		mActionTimersMap.insert(LLSpeakerActionTimer::action_value_t(speaker_id, +			new LLSpeakerActionTimer( +				boost::bind(&LLSpeakersDelayActionsStorage::onTimerActionCallback, this, _1), +				mActionDelay, speaker_id))); +	} +} + +void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) +{ +	if (mActionTimersMap.size() == 0) return; + +	LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); + +	if (it_speaker != mActionTimersMap.end()) +	{ +		delete it_speaker->second; +		mActionTimersMap.erase(it_speaker); +	} +} + +void LLSpeakersDelayActionsStorage::removeAllTimers() +{ +	LLSpeakerActionTimer::action_timer_iter_t iter = mActionTimersMap.begin(); +	for (; iter != mActionTimersMap.end(); ++iter) +	{ +		delete iter->second; +	} +	mActionTimersMap.clear(); +} + +bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_id) +{ +	unsetActionTimer(speaker_id); + +	if (mActionCallback) +	{ +		mActionCallback(speaker_id); +	} + +	// do not return true to avoid deleting of an timer twice: +	// in LLSpeakersDelayActionsStorage::unsetActionTimer() & LLEventTimer::updateClass() +	return false; +} +  //  // LLSpeakerMgr @@ -172,10 +252,14 @@ bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPo  LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :   	mVoiceChannel(channelp)  { +	static LLUICachedControl<F32> remove_delay ("SpeakerParticipantRemoveDelay", 10.0); + +	mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay);  }  LLSpeakerMgr::~LLSpeakerMgr()  { +	delete mSpeakerDelayRemover;  }  LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) @@ -198,7 +282,6 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin  		{  			// keep highest priority status (lowest value) instead of overriding current value  			speakerp->mStatus = llmin(speakerp->mStatus, status); -			speakerp->mActivityTimer.resetWithExpiry(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 @@ -210,6 +293,8 @@ LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::strin  		}  	} +	mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); +  	return speakerp;  } @@ -314,7 +399,7 @@ void LLSpeakerMgr::update(BOOL resort_ok)  	S32 sort_index = 0;  	speaker_list_t::iterator sorted_speaker_it;  	for(sorted_speaker_it = mSpeakersSorted.begin();  -		sorted_speaker_it != mSpeakersSorted.end(); ) +		sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)  	{  		LLPointer<LLSpeaker> speakerp = *sorted_speaker_it; @@ -327,19 +412,6 @@ void LLSpeakerMgr::update(BOOL resort_ok)  		// 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; -		}  	}  } @@ -363,6 +435,35 @@ void LLSpeakerMgr::updateSpeakerList()  	}  } +void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp) +{ +	speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +	speakerp->mDotColor = INACTIVE_COLOR; +	mSpeakerDelayRemover->setActionTimer(speakerp->mID); +} + +bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) +{ +	mSpeakers.erase(speaker_id); + +	speaker_list_t::iterator sorted_speaker_it = mSpeakersSorted.begin(); +	 +	for(; sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) +	{ +		if (speaker_id == (*sorted_speaker_it)->mID) +		{ +			mSpeakersSorted.erase(sorted_speaker_it); +			break; +		} +	} + +	fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); + +	update(TRUE); + +	return false; +} +  LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id)  {  	//In some conditions map causes crash if it is empty(Windows only), adding check (EK) @@ -511,9 +612,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  			{  				if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull())  				{ -					speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; -					speakerp->mDotColor = INACTIVE_COLOR; -					speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +					setSpeakerNotInChannel(speakerp);  				}  				else if (agent_data["transition"].asString() == "ENTER")  				{ @@ -563,9 +662,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  			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.resetWithExpiry(SPEAKER_TIMEOUT); +				setSpeakerNotInChannel(speakerp);  			}  			else if ( agent_transition == "ENTER")  			{ @@ -734,12 +831,13 @@ void LLActiveSpeakerMgr::updateSpeakerList()  	mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel();  	// always populate from active voice channel -	if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) +	if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false  	{  		fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear");  		mSpeakers.clear();  		mSpeakersSorted.clear();  		mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); +		mSpeakerDelayRemover->removeAllTimers();  	}  	LLSpeakerMgr::updateSpeakerList(); @@ -800,9 +898,7 @@ void LLLocalSpeakerMgr::updateSpeakerList()  			LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(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.resetWithExpiry(SPEAKER_TIMEOUT); +				setSpeakerNotInChannel(speakerp);  			}  		}  	} diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index da8dfdf548..63237204c8 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -73,7 +73,6 @@ public:  	F32				mLastSpokeTime;		// timestamp when this speaker last spoke  	F32				mSpeechVolume;		// current speech amplitude (timea average rms amplitude?)  	std::string		mDisplayName;		// cache user name for this speaker -	LLFrameTimer	mActivityTimer;	// time out speakers when they are not part of current voice channel  	BOOL			mHasSpoken;			// has this speaker said anything this session?  	BOOL			mHasLeftCurrentCall;	// has this speaker left the current voice call?  	LLColor4		mDotColor; @@ -120,6 +119,92 @@ private:  	const LLUUID& mSpeakerID;  }; +/** + * class LLSpeakerActionTimer + *  + * Implements a timer that calls stored callback action for stored speaker after passed period. + * + * Action is called until callback returns "true". + * In this case the timer will be removed via LLEventTimer::updateClass(). + * Otherwise it should be deleted manually in place where it is used. + * If action callback is not set timer will tick only once and deleted. + */ +class LLSpeakerActionTimer : public LLEventTimer +{ +public: +	typedef boost::function<bool(const LLUUID&)>	action_callback_t; +	typedef std::map<LLUUID, LLSpeakerActionTimer*> action_timers_map_t; +	typedef action_timers_map_t::value_type			action_value_t; +	typedef action_timers_map_t::const_iterator		action_timer_const_iter_t; +	typedef action_timers_map_t::iterator			action_timer_iter_t; + +	/** +	 * Constructor. +	 * +	 * @param action_cb - callback which will be called each time after passed action period. +	 * @param action_period - time in seconds timer should tick. +	 * @param speaker_id - LLUUID of speaker which will be passed into action callback. +	 */ +	LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); +	virtual ~LLSpeakerActionTimer() {}; + +	/** +	 * Implements timer "tick". +	 * +	 * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). +	 */ +	virtual BOOL tick(); + +private: +	action_callback_t	mActionCallback; +	LLUUID				mSpeakerId; +}; + +/** + * Represents a functionality to store actions for speakers with delay. + * Is based on LLSpeakerActionTimer. + */ +class LLSpeakersDelayActionsStorage +{ +public: +	LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay); +	~LLSpeakersDelayActionsStorage(); + +	/** +	 * Sets new LLSpeakerActionTimer with passed speaker UUID. +	 */ +	void setActionTimer(const LLUUID& speaker_id); + +	/** +	 * Removes stored LLSpeakerActionTimer for passed speaker UUID from internal map and deletes it. +	 * +	 * @see onTimerActionCallback() +	 */ +	void unsetActionTimer(const LLUUID& speaker_id); + +	void removeAllTimers(); +private: +	/** +	 * Callback of the each instance of LLSpeakerActionTimer. +	 * +	 * Unsets an appropriate timer instance and calls action callback for specified speacker_id. +	 * It always returns false to not use LLEventTimer::updateClass functionality of timer deleting. +	 * +	 * @see unsetActionTimer() +	 */ +	bool onTimerActionCallback(const LLUUID& speaker_id); + +	LLSpeakerActionTimer::action_timers_map_t	mActionTimersMap; +	LLSpeakerActionTimer::action_callback_t		mActionCallback; + +	/** +	 * Delay to call action callback for speakers after timer was set. +	 */ +	F32	mActionDelay; + +}; + +  class LLSpeakerMgr : public LLOldEvents::LLObservable  {  public: @@ -144,6 +229,8 @@ public:  protected:  	virtual void updateSpeakerList(); +	void setSpeakerNotInChannel(LLSpeaker* speackerp); +	bool removeSpeaker(const LLUUID& speaker_id);  	typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;  	speaker_map_t		mSpeakers; @@ -151,6 +238,11 @@ protected:  	speaker_list_t		mSpeakersSorted;  	LLFrameTimer		mSpeechTimer;  	LLVoiceChannel*		mVoiceChannel; + +	/** +	 * time out speakers when they are not part of current session +	 */ +	LLSpeakersDelayActionsStorage* mSpeakerDelayRemover;  };  class LLIMSpeakerMgr : public LLSpeakerMgr | 
