diff options
| -rwxr-xr-x | indra/newview/llvoicevivox.cpp | 314 | ||||
| -rwxr-xr-x | indra/newview/llvoicevivox.h | 59 | 
2 files changed, 284 insertions, 89 deletions
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e9e004f492..0239a8ad21 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -25,6 +25,7 @@   */  #include "llviewerprecompiledheaders.h" +#include <algorithm>  #include "llvoicevivox.h"  #include "llsdutil.h" @@ -3134,7 +3135,7 @@ void LLVivoxVoiceClient::sessionRemovedEvent(  		leftAudioSession(session);  		// This message invalidates the session's handle.  Set it to empty. -		setSessionHandle(session); +        clearSessionHandle(session);  		// This also means that the session's session group is now empty.  		// Terminate the session group so it doesn't leak. @@ -4164,6 +4165,8 @@ void LLVivoxVoiceClient::callUser(const LLUUID &uuid)  	switchChannel(userURI, false, true, true);  } +#if 0 +// Vivox text IMs are not in use.  LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::startUserIMSession(const LLUUID &uuid)  {  	// Figure out if a session with the user already exists @@ -4197,11 +4200,14 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::startUserIMSession(con  	return session;  } - +#endif  void LLVivoxVoiceClient::endUserIMSession(const LLUUID &uuid)  { -	// Figure out if a session with the user exists +#if 0 +    // Vivox text IMs are not in use. +     +    // Figure out if a session with the user exists      sessionStatePtr_t session(findSession(uuid));  	if(session)  	{ @@ -4215,6 +4221,7 @@ void LLVivoxVoiceClient::endUserIMSession(const LLUUID &uuid)  	{  		LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL;  	} +#endif  }  bool LLVivoxVoiceClient::isValidChannel(std::string &sessionHandle)  { @@ -4256,7 +4263,7 @@ BOOL LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id)  	BOOL result = TRUE;       sessionStatePtr_t session(findSession(id)); -	if(session != NULL) +	if(session)  	{  		// this is a p2p session with the indicated caller, or the session with the specified UUID.  		if(session->mSynthesizedCallerID) @@ -4265,10 +4272,10 @@ BOOL LLVivoxVoiceClient::isParticipantAvatar(const LLUUID &id)  	else  	{  		// Didn't find a matching session -- check the current audio session for a matching participant -		if(mAudioSession != NULL) +		if(mAudioSession)  		{              participantStatePtr_t participant(findParticipantByID(id)); -			if(participant != NULL) +			if(participant)  			{  				result = participant->isAvatar();  			} @@ -5027,29 +5034,49 @@ void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed)  	// TODO: Implement once Vivox gives me a sample  } +//------------------------------------------------------------------------ +std::set<LLVivoxVoiceClient::sessionState::wptr_t> LLVivoxVoiceClient::sessionState::mSession; + +  LLVivoxVoiceClient::sessionState::sessionState() : -        mErrorStatusCode(0), -	mMediaStreamState(streamStateUnknown), -	//mTextStreamState(streamStateUnknown), -	mCreateInProgress(false), -	mMediaConnectInProgress(false), -	mVoiceInvitePending(false), -	mTextInvitePending(false), -	mSynthesizedCallerID(false), -	mIsChannel(false), -	mIsSpatial(false), -	mIsP2P(false), -	mIncoming(false), -	mVoiceEnabled(false), -	mReconnect(false), -	mVolumeDirty(false), -	mMuteDirty(false), -	mParticipantsChanged(false) +    mErrorStatusCode(0), +    mMediaStreamState(streamStateUnknown), +    mCreateInProgress(false), +    mMediaConnectInProgress(false), +    mVoiceInvitePending(false), +    mTextInvitePending(false), +    mSynthesizedCallerID(false), +    mIsChannel(false), +    mIsSpatial(false), +    mIsP2P(false), +    mIncoming(false), +    mVoiceEnabled(false), +    mReconnect(false), +    mVolumeDirty(false), +    mMuteDirty(false), +    mParticipantsChanged(false) +{ +} + +/*static*/ +LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::createSession()  { +    sessionState::ptr_t ptr(new sessionState()); + +    std::pair<std::set<wptr_t>::iterator, bool>  result = mSession.insert(ptr); + +    if (result.second) +        ptr->mMyIterator = result.first; + +    return ptr;  }  LLVivoxVoiceClient::sessionState::~sessionState()  { +    LL_INFOS("Voice") << "Destroying session handle=" << mHandle << " SIP=" << mSIPURI << LL_ENDL; +    if (mMyIterator != mSession.end()) +        mSession.erase(mMyIterator); +  	removeAllParticipants();  } @@ -5068,16 +5095,112 @@ bool LLVivoxVoiceClient::sessionState::isTextIMPossible()  } -LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsBegin(void) +/*static*/  +LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByHandle(const std::string &handle) +{ +    sessionStatePtr_t result; + +    // *TODO: My kingdom for a lambda! +    std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByHandle, _1, handle)); + +    if (it != mSession.end()) +        result = (*it).lock(); + +    return result; +} + +/*static*/  +LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchCreatingSessionByURI(const std::string &uri) +{ +    sessionStatePtr_t result; + +    // *TODO: My kingdom for a lambda! +    std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCreatingURI, _1, uri)); + +    if (it != mSession.end()) +        result = (*it).lock(); + +    return result; +} + +/*static*/ +LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByURI(const std::string &uri) +{ +    sessionStatePtr_t result; + +    // *TODO: My kingdom for a lambda! +    std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testBySIPOrAlterateURI, _1, uri)); + +    if (it != mSession.end()) +        result = (*it).lock(); + +    return result; +} + +/*static*/ +LLVivoxVoiceClient::sessionState::ptr_t LLVivoxVoiceClient::sessionState::matchSessionByParticipant(const LLUUID &participant_id) +{ +    sessionStatePtr_t result; + +    // *TODO: My kingdom for a lambda! +    std::set<wptr_t>::iterator it = std::find_if(mSession.begin(), mSession.end(), boost::bind(testByCallerId, _1, participant_id)); + +    if (it != mSession.end()) +        result = (*it).lock(); + +    return result; +} + +void LLVivoxVoiceClient::sessionState::for_each(sessionFunc_t func) +{ +    std::for_each(mSession.begin(), mSession.end(), boost::bind(for_eachPredicate, _1, func)); +} + +// simple test predicates.   +// *TODO: These should be made into lambdas when we can pull the trigger on newer C++ features. +bool LLVivoxVoiceClient::sessionState::testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle)  { -	return mSessions.begin(); +    ptr_t aLock(a.lock()); + +    return aLock ? aLock->mHandle == handle : false; +} + +bool LLVivoxVoiceClient::sessionState::testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri) +{ +    ptr_t aLock(a.lock()); + +    return aLock ? (aLock->mCreateInProgress && (aLock->mSIPURI == uri)) : false; +} + +bool LLVivoxVoiceClient::sessionState::testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri) +{ +    ptr_t aLock(a.lock()); + +    return aLock ? ((aLock->mSIPURI == uri) || (aLock->mAlternateSIPURI == uri)) : false;  } -LLVivoxVoiceClient::sessionIterator LLVivoxVoiceClient::sessionsEnd(void) + +bool LLVivoxVoiceClient::sessionState::testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId)  { -	return mSessions.end(); +    ptr_t aLock(a.lock()); + +    return aLock ? ((aLock->mCallerID == participantId) || (aLock->mIMSessionID == participantId)) : false;  } +/*static*/ +void LLVivoxVoiceClient::sessionState::for_eachPredicate(const LLVivoxVoiceClient::sessionState::wptr_t &a, sessionFunc_t func) +{ +    ptr_t aLock(a.lock()); + +    if (aLock) +        func(aLock); +    else +    { +        LL_WARNS("Voice") << "Stale handle in session map!" << LL_ENDL; +    } +} + +  LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const std::string &handle)  { @@ -5093,33 +5216,14 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const std:  LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)  {	 -    sessionStatePtr_t result; -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -        sessionStatePtr_t session = *iter; -		if(session->mCreateInProgress && (session->mSIPURI == uri)) -		{ -			result = session; -			break; -		} -	} +    sessionStatePtr_t result = sessionState::matchCreatingSessionByURI(uri);  	return result;  }  LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::findSession(const LLUUID &participant_id)  { -    sessionStatePtr_t result; -	 -	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -	{ -        sessionStatePtr_t session = *iter; -		if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id)) -		{ -			result = session; -			break; -		} -	} +    sessionStatePtr_t result = sessionState::matchSessionByParticipant(participant_id);  	return result;  } @@ -5130,18 +5234,9 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::  	if(handle.empty())  	{ -		// No handle supplied. -		// Check whether there's already a session with this URI -		for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) -		{ -            sessionStatePtr_t s(*iter); -			if((s->mSIPURI == uri) || (s->mAlternateSIPURI == uri)) -			{ -				// TODO: I need to think about this logic... it's possible that this case should raise an internal error. -				result = s; -				break; -			} -		} +        // No handle supplied. +        // Check whether there's already a session with this URI +        result = sessionState::matchSessionByURI(uri);  	}  	else // (!handle.empty())  	{ @@ -5158,8 +5253,8 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::  	{  		// No existing session found. -		LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL; -        result.reset(new sessionState()); +		LL_DEBUGS("Voice") << "adding new session: handle \"" << handle << "\" URI " << uri << LL_ENDL; +        result = sessionState::createSession();  		result->mSIPURI = uri;  		result->mHandle = handle; @@ -5168,10 +5263,11 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::  			result->mVoiceFontID = LLVoiceClient::instance().getVoiceEffectDefault();  		} -		mSessions.insert(result); -  		if(!result->mHandle.empty())  		{ +            // *TODO: Rider: This concerns me.  There is a path (via switchChannel) where  +            // we do not track the session.  In theory this means that we could end up with  +            // a mAuidoSession that does not match the session tracked in mSessionsByHandle  			mSessionsByHandle.insert(sessionMap::value_type(result->mHandle, result));  		}  	} @@ -5209,6 +5305,30 @@ LLVivoxVoiceClient::sessionStatePtr_t LLVivoxVoiceClient::addSession(const std::  	return result;  } +void LLVivoxVoiceClient::clearSessionHandle(const sessionStatePtr_t &session) +{ +    if (session) +    { +        if (session->mHandle.empty()) +        { +            sessionMap::iterator iter = mSessionsByHandle.find(session->mHandle); +            if (iter != mSessionsByHandle.end()) +            { +                mSessionsByHandle.erase(iter); +            } +        } +        else +        { +            LL_WARNS("Voice") << "Session has empty handle!" << LL_ENDL; +        } +    } +    else +    { +        LL_WARNS("Voice") << "Attempt to clear NULL session!" << LL_ENDL; +    } + +} +  void LLVivoxVoiceClient::setSessionHandle(const sessionStatePtr_t &session, const std::string &handle)  {  	// Have to remove the session from the handle-indexed map before changing the handle, or things will break badly. @@ -5221,14 +5341,14 @@ void LLVivoxVoiceClient::setSessionHandle(const sessionStatePtr_t &session, cons  		{  			if(iter->second != session)  			{ -				LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL; +				LL_ERRS("Voice") << "Internal error: session mismatch! Session may have been duplicated." << LL_ENDL;  			}  			mSessionsByHandle.erase(iter);  		}  		else  		{ -			LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL; +            LL_WARNS("Voice") << "Attempt to remove session with handle " << session->mHandle << " not found in map!" << LL_ENDL;  		}  	} @@ -5266,9 +5386,6 @@ void LLVivoxVoiceClient::deleteSession(const sessionStatePtr_t &session)  		}  	} -	// Remove the session from the URI map -	mSessions.erase(session); -	  	// At this point, the session should be unhooked from all lists and all state should be consistent.  	verifySessionState(); @@ -5285,27 +5402,23 @@ void LLVivoxVoiceClient::deleteSession(const sessionStatePtr_t &session)  		mNextAudioSession.reset();  	} -	// delete the session -	//delete session;  }  void LLVivoxVoiceClient::deleteAllSessions()  {  	LL_DEBUGS("Voice") << "called" << LL_ENDL; -	while(!mSessions.empty()) +     +    while (!mSessionsByHandle.empty())  	{ -		deleteSession(*(sessionsBegin())); +        deleteSession(mSessionsByHandle.begin()->second);  	} -	if(!mSessionsByHandle.empty()) -	{ -		LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL; -	}  }  void LLVivoxVoiceClient::verifySessionState(void)  { +#if 0  	// This is mostly intended for debugging problems with session state management.  	LL_DEBUGS("Voice") << "Total session count: " << mSessions.size() << " , session handle map size: " << mSessionsByHandle.size() << LL_ENDL; @@ -5332,7 +5445,9 @@ void LLVivoxVoiceClient::verifySessionState(void)  			}  		}  	} +#endif +#if 0  	// check that every entry in the handle map points to a valid session in the session set  	for(sessionMap::iterator iter = mSessionsByHandle.begin(); iter != mSessionsByHandle.end(); iter++)  	{ @@ -5350,6 +5465,7 @@ void LLVivoxVoiceClient::verifySessionState(void)  			}  		}  	} +#endif  }  void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) @@ -5500,8 +5616,51 @@ void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id,  	avatarNameResolved(agent_id, display_name);  } +void LLVivoxVoiceClient::predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name) +{ +    participantStatePtr_t participant(session->findParticipantByID(id)); +    if (participant) +    { +        // Found -- fill in the name +        participant->mAccountName = name; +        // and post a "participants updated" message to listeners later. +        session->mParticipantsChanged = true; +    } + +    // Check whether this is a p2p session whose caller name just resolved +    if (session->mCallerID == id) +    { +        // this session's "caller ID" just resolved.  Fill in the name. +        session->mName = name; +        if (session->mTextInvitePending) +        { +            session->mTextInvitePending = false; + +            // We don't need to call LLIMMgr::getInstance()->addP2PSession() here.  The first incoming message will create the panel.				 +        } +        if (session->mVoiceInvitePending) +        { +            session->mVoiceInvitePending = false; + +            LLIMMgr::getInstance()->inviteToSession( +                session->mIMSessionID, +                session->mName, +                session->mCallerID, +                session->mName, +                IM_SESSION_P2P_INVITE, +                LLIMMgr::INVITATION_TYPE_VOICE, +                session->mHandle, +                session->mSIPURI); +        } + +    } +} +  void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)  { +#if 1 +    sessionState::for_each(boost::bind(predAvatarNameResolution, _1, id, name)); +#else  	// Iterate over all sessions.  	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)  	{ @@ -5544,6 +5703,7 @@ void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string  		}  	} +#endif  }  bool LLVivoxVoiceClient::setVoiceEffect(const LLUUID& id) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 0054c7cca4..1e59a337f5 100755 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -116,7 +116,7 @@ public:  	// close any existing text IM session with the specified user  	virtual void endUserIMSession(const LLUUID &uuid); -	 +  	// Returns true if calling back the session URI after the session has closed is possible.  	// Currently this will be false only for PSTN P2P calls.		  	// NOTE: this will return true if the session can't be found.  @@ -256,6 +256,7 @@ protected:  	friend class LLVivoxVoiceClientMuteListObserver;  	friend class LLVivoxVoiceClientFriendsObserver;	 +  	enum streamState  	{ @@ -302,22 +303,32 @@ protected:  	struct sessionState  	{ -	public: -		sessionState(); +    public: +        typedef boost::shared_ptr<sessionState> ptr_t; +        typedef boost::weak_ptr<sessionState> wptr_t; + +        typedef boost::function<void(const ptr_t &)> sessionFunc_t; + +        static ptr_t createSession();  		~sessionState();          participantStatePtr_t addParticipant(const std::string &uri); -		// Note: after removeParticipant returns, the participant* that was passed to it will have been deleted. -		// Take care not to use the pointer again after that.          void removeParticipant(const participantStatePtr_t &participant);  		void removeAllParticipants(); -		 +          participantStatePtr_t findParticipant(const std::string &uri);          participantStatePtr_t findParticipantByID(const LLUUID& id); -		 + +        static ptr_t matchSessionByHandle(const std::string &handle); +        static ptr_t matchCreatingSessionByURI(const std::string &uri); +        static ptr_t matchSessionByURI(const std::string &uri); +        static ptr_t matchSessionByParticipant(const LLUUID &participant_id); +  		bool isCallBackPossible();  		bool isTextIMPossible(); +        static void for_each(sessionFunc_t func); +  		std::string mHandle;  		std::string mGroupHandle;  		std::string mSIPURI; @@ -354,6 +365,20 @@ protected:  		participantUUIDMap mParticipantsByUUID;  		LLUUID		mVoiceFontID; + +    private: +        sessionState(); + +        static std::set<wptr_t> mSession;   // canonical list of outstanding sessions. +        std::set<wptr_t>::iterator  mMyIterator;    // used for delete + +        static void for_eachPredicate(const wptr_t &a, sessionFunc_t func); + +        static bool testByHandle(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string handle); +        static bool testByCreatingURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri); +        static bool testBySIPOrAlterateURI(const LLVivoxVoiceClient::sessionState::wptr_t &a, std::string uri); +        static bool testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId); +  	};      typedef boost::shared_ptr<sessionState> sessionStatePtr_t; @@ -362,7 +387,9 @@ protected:  	///////////////////////////////////////////////////////  	// Private Member Functions  	////////////////////////////////////////////////////// -	 + + +  	//////////////////////////////  	/// @name TVC/Server management and communication  	//@{ @@ -479,6 +506,7 @@ protected:      participantStatePtr_t findParticipantByID(const LLUUID& id); +#if 0  	////////////////////////////////////////  	// voice sessions.      typedef std::set<sessionStatePtr_t> sessionSet; @@ -486,14 +514,15 @@ protected:  	typedef sessionSet::iterator sessionIterator;  	sessionIterator sessionsBegin(void);  	sessionIterator sessionsEnd(void); +#endif      sessionStatePtr_t findSession(const std::string &handle);      sessionStatePtr_t findSessionBeingCreatedByURI(const std::string &uri);      sessionStatePtr_t findSession(const LLUUID &participant_id); -    sessionStatePtr_t findSessionByCreateID(const std::string &create_id); -    sessionStatePtr_t addSession(const std::string &uri, const std::string &handle = LLStringUtil::null); -    void setSessionHandle(const sessionStatePtr_t &session, const std::string &handle = LLStringUtil::null); +    sessionStatePtr_t addSession(const std::string &uri, const std::string &handle = std::string()); +    void clearSessionHandle(const sessionStatePtr_t &session); +    void setSessionHandle(const sessionStatePtr_t &session, const std::string &handle);      void setSessionURI(const sessionStatePtr_t &session, const std::string &uri);      void deleteSession(const sessionStatePtr_t &session);  	void deleteAllSessions(void); @@ -564,6 +593,8 @@ protected:  	void lookupName(const LLUUID &id);  	void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);  	void avatarNameResolved(const LLUUID &id, const std::string &name); +    static void predAvatarNameResolution(const LLVivoxVoiceClient::sessionStatePtr_t &session, LLUUID id, std::string name); +  	boost::signals2::connection mAvatarNameCacheConnection;  	///////////////////////////// @@ -675,7 +706,9 @@ private:  	int mLoginRetryCount;  	sessionMap mSessionsByHandle;				// Active sessions, indexed by session handle.  Sessions which are being initiated may not be in this map. +#if 0  	sessionSet mSessions;						// All sessions, not indexed.  This is the canonical session list. +#endif  	bool mBuddyListMapPopulated;  	bool mBlockRulesListReceived; @@ -720,10 +753,12 @@ private:  	void sendFriendsListUpdates(); +#if 0  	// start a text IM session with the specified user  	// This will be asynchronous, the session may be established at a future time.      sessionStatePtr_t startUserIMSession(const LLUUID& uuid); -	 +#endif +  	void enforceTether(void);  	bool		mSpatialCoordsDirty;  | 
