summaryrefslogtreecommitdiff
path: root/indra/newview/llvoicevivox.cpp
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2016-01-25 17:10:29 -0800
committerRider Linden <rider@lindenlab.com>2016-01-25 17:10:29 -0800
commitcf77fea0cd7aff5eef6de69115ec6a296a025934 (patch)
tree82a60a0bf1a1bc630c434e08b4210095ea67becd /indra/newview/llvoicevivox.cpp
parentde81e34dc6049d502031d7de380cdd7d6fa2f458 (diff)
MAINT-6086: Reworked how sessions were being tracked and recovered. A case was occurring where a session was being created and then destroyed, but had never been added to the session tracking map.
Diffstat (limited to 'indra/newview/llvoicevivox.cpp')
-rwxr-xr-xindra/newview/llvoicevivox.cpp314
1 files changed, 237 insertions, 77 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)