Files
SingularityViewer/indra/newview/llspeakers.h
2020-01-15 12:57:58 -05:00

412 lines
12 KiB
C++

/**
* @file llspeakers.h
* @brief Management interface for muting and controlling volume of residents currently speaking
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLSPEAKERS_H
#define LL_LLSPEAKERS_H
#include "llevent.h"
#include "lleventtimer.h"
#include "llhandle.h"
class LLAvatarName;
class LLSpeakerMgr;
class LLVoiceChannel;
// data for a given participant in a voice channel
class LLSpeaker final : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable
{
public:
typedef enum e_speaker_type
{
SPEAKER_AGENT,
SPEAKER_OBJECT,
SPEAKER_EXTERNAL // Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group)
} ESpeakerType;
typedef enum e_speaker_status
{
STATUS_SPEAKING,
STATUS_HAS_SPOKEN,
STATUS_VOICE_ACTIVE,
STATUS_TEXT_ONLY,
STATUS_NOT_IN_CHANNEL,
STATUS_MUTED
} ESpeakerStatus;
struct speaker_entry_t
{
speaker_entry_t(const LLUUID& id,
LLSpeaker::ESpeakerType type = ESpeakerType::SPEAKER_AGENT,
LLSpeaker::ESpeakerStatus status = ESpeakerStatus::STATUS_TEXT_ONLY,
const boost::optional<bool> moderator = boost::none,
const boost::optional<bool> moderator_muted_text = boost::none,
std::string name = std::string()) :
id(id),
type(type),
status(status),
moderator(moderator),
moderator_muted_text(moderator_muted_text),
name(name)
{}
const LLUUID id;
const LLSpeaker::ESpeakerType type;
const LLSpeaker::ESpeakerStatus status;
const boost::optional<bool> moderator;
const boost::optional<bool> moderator_muted_text;
const std::string name;
};
LLSpeaker(const speaker_entry_t& entry);
~LLSpeaker() = default;
void update(const speaker_entry_t& entry);
void lookupName();
void onNameCache(const LLAvatarName& full_name);
bool isInVoiceChannel();
void setStatus(ESpeakerStatus status)
{
if (status != mStatus)
{
mStatus = status;
mNeedsResort = true;
}
}
void setName(const std::string& name)
{
if (name != mDisplayName)
{
mDisplayName = name;
mNeedsResort = true;
}
}
void setSpokenTime(F32 time)
{
if (mLastSpokeTime != time)
{
mLastSpokeTime = time;
mNeedsResort = true;
}
}
LLUUID mID;
ESpeakerStatus mStatus; // current activity status in speech group
ESpeakerType mType : 2;
bool mIsModerator : 1;
bool mModeratorMutedVoice : 1;
bool mModeratorMutedText : 1;
bool mHasSpoken : 1; // has this speaker said anything this session?
bool mHasLeftCurrentCall : 1; // has this speaker left the current voice call?
bool mTyping : 1;
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
LLColor4 mDotColor;
bool mNeedsResort;
S32 mSortIndex;
};
class LLSpeakerUpdateSpeakerEvent final : public LLOldEvents::LLEvent
{
public:
LLSpeakerUpdateSpeakerEvent(LLSpeaker* source);
/*virtual*/ LLSD getValue() override;
private:
const LLUUID& mSpeakerID;
};
class LLSpeakerUpdateModeratorEvent final : public LLOldEvents::LLEvent
{
public:
LLSpeakerUpdateModeratorEvent(LLSpeaker* source);
/*virtual*/ LLSD getValue() override;
private:
const LLUUID& mSpeakerID;
BOOL mIsModerator;
};
class LLSpeakerTextModerationEvent final : public LLOldEvents::LLEvent
{
public:
LLSpeakerTextModerationEvent(LLSpeaker* source);
/*virtual*/ LLSD getValue() override;
};
class LLSpeakerVoiceModerationEvent final : public LLOldEvents::LLEvent
{
public:
LLSpeakerVoiceModerationEvent(LLSpeaker* source);
/*virtual*/ LLSD getValue() override;
};
class LLSpeakerListChangeEvent final : public LLOldEvents::LLEvent
{
public:
LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id);
/*virtual*/ LLSD getValue() override;
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 final : public LLEventTimer
{
public:
typedef std::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() = default;
/**
* Implements timer "tick".
*
* If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass().
*/
BOOL tick() override;
/**
* Clears the callback.
*
* Use this instead of deleteing this object.
* The next call to tick() will return true and that will destroy this object.
*/
void unset();
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 optionally deletes it.
*
* @see onTimerActionCallback()
*/
void unsetActionTimer(const LLUUID& speaker_id);
void removeAllTimers();
bool isTimerStarted(const LLUUID& speaker_id);
private:
/**
* Callback of the each instance of LLSpeakerActionTimer.
*
* Unsets an appropriate timer instance and calls action callback for specified speacker_id.
*
* @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
{
LOG_CLASS(LLSpeakerMgr);
public:
typedef LLSpeaker::speaker_entry_t speaker_entry_t;
LLSpeakerMgr(LLVoiceChannel* channelp);
virtual ~LLSpeakerMgr();
LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id);
void update(BOOL resort_ok);
void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing);
void speakerChatted(const LLUUID& speaker_id);
void setSpeakers(const std::vector<speaker_entry_t>& speakers);
LLPointer<LLSpeaker> setSpeaker(const speaker_entry_t& speakers);
BOOL isVoiceActive() const;
typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t;
void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text);
LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; }
const LLUUID getSessionID() const;
bool isSpeakerToBeRemoved(const LLUUID& speaker_id) const;
/**
* Removes avaline speaker.
*
* This is a HACK due to server does not send information that Avaline caller ends call.
* It can be removed when server is updated. See EXT-4301 for details
*/
bool removeAvalineSpeaker(const LLUUID& speaker_id) { return removeSpeaker(speaker_id); }
/**
* Initializes mVoiceModerated depend on LLSpeaker::mModeratorMutedVoice of agent's participant.
*
* Is used only to implement workaround to initialize mVoiceModerated on first join to group chat. See EXT-6937
*/
void initVoiceModerateMode();
protected:
virtual void updateSpeakerList();
void setSpeakerNotInChannel(LLPointer<LLSpeaker> speackerp);
bool removeSpeaker(const LLUUID& speaker_id);
typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t;
speaker_map_t mSpeakers;
bool mSpeakerListUpdated;
LLTimer mGetListTime;
speaker_list_t mSpeakersSorted;
LLFrameTimer mSpeechTimer;
LLVoiceChannel* mVoiceChannel;
/**
* time out speakers when they are not part of current session
*/
LLSpeakersDelayActionsStorage* mSpeakerDelayRemover;
// *TODO: should be moved back into LLIMSpeakerMgr when a way to request the current voice channel
// moderation mode is implemented: See EXT-6937
bool mVoiceModerated;
// *TODO: To be removed when a way to request the current voice channel
// moderation mode is implemented: See EXT-6937
bool mModerateModeHandledFirstTime;
};
class LLIMSpeakerMgr final : public LLSpeakerMgr
{
LOG_CLASS(LLIMSpeakerMgr);
public:
LLIMSpeakerMgr(LLVoiceChannel* channel);
void updateSpeakers(const LLSD& update);
void setSpeakers(const LLSD& speakers);
void toggleAllowTextChat(const LLUUID& speaker_id);
/**
* Mutes/Unmutes avatar for current group voice chat.
*
* It only marks avatar as muted for session and does not use local Agent's Block list.
* It does not mute Agent itself.
*
* @param[in] avatar_id UUID of avatar to be processed
* @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted.
*
* @see moderateVoiceAllParticipants()
*/
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
/**
* Mutes/Unmutes all avatars for current group voice chat.
*
* It only marks avatars as muted for session and does not use local Agent's Block list.
* It calls forceVoiceModeratedMode() in case of session is already in requested state.
*
* @param[in] unmute_everyone if false - avatars will be muted, otherwise - unmuted.
*
* @see moderateVoiceParticipant()
*/
void moderateVoiceAllParticipants(bool unmute_everyone);
void processSessionUpdate(const LLSD& session_update);
protected:
void updateSpeakerList() override;
void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice);
/**
* Process all participants to mute/unmute them according to passed voice session state.
*/
void forceVoiceModeratedMode(bool should_be_muted);
};
class LLActiveSpeakerMgr final : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
{
LOG_CLASS(LLActiveSpeakerMgr);
public:
LLActiveSpeakerMgr();
protected:
void updateSpeakerList() override;
};
class LLLocalSpeakerMgr final : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr>
{
LOG_CLASS(LLLocalSpeakerMgr);
public:
LLLocalSpeakerMgr();
~LLLocalSpeakerMgr ();
protected:
void updateSpeakerList() override;
};
#endif // LL_LLSPEAKERS_H