llvoiceclient.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:192k
- }
- }
- void LLVoiceClient::clearAllLists()
- {
- // FOR TESTING ONLY
-
- // This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about.
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
- {
- buddyListEntry *buddy = buddy_it->second;
- buddy_it++;
-
- std::ostringstream stream;
- if(buddy->mInVivoxBuddies)
- {
- // delete this entry from the vivox buddy list
- buddy->mInVivoxBuddies = false;
- LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.BuddyDelete.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "</Request>nnn";
- }
- if(buddy->mHasBlockListEntry)
- {
- // Delete the associated block list entry (so the block list doesn't fill up with junk)
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteBlockRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>nnn";
- }
- if(buddy->mHasAutoAcceptListEntry)
- {
- // Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk)
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteAutoAcceptRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>nnn";
- }
- writeString(stream.str());
- }
- }
- void LLVoiceClient::sendFriendsListUpdates()
- {
- if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty)
- {
- mFriendsListDirty = false;
-
- if(0)
- {
- // FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries.
- clearAllLists();
- return;
- }
-
- LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL;
-
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- // reset the temp flags in the local buddy list
- buddy_it->second->mInSLFriends = false;
- }
-
- // correlate with the friends list
- {
- LLCollectAllBuddies collect;
- LLAvatarTracker::instance().applyFunctor(collect);
- LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin();
- LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end();
-
- for ( ; it != end; ++it)
- {
- checkFriend(it->second);
- }
- it = collect.mOffline.begin();
- end = collect.mOffline.end();
- for ( ; it != end; ++it)
- {
- checkFriend(it->second);
- }
- }
-
- LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();)
- {
- buddyListEntry *buddy = buddy_it->second;
- buddy_it++;
-
- // Ignore entries that aren't resolved yet.
- if(buddy->mNameResolved)
- {
- std::ostringstream stream;
- if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate))
- {
- if(mNumberOfAliases > 0)
- {
- // Add (or update) this entry in the vivox buddy list
- buddy->mInVivoxBuddies = true;
- buddy->mNeedsNameUpdate = false;
- LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="Account.BuddySet.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "<DisplayName>" << buddy->mDisplayName << "</DisplayName>"
- << "<BuddyData></BuddyData>" // Without this, SLVoice doesn't seem to parse the command.
- << "<GroupID>0</GroupID>"
- << "</Request>nnn";
- }
- }
- else if(!buddy->mInSLFriends)
- {
- // This entry no longer exists in your SL friends list. Remove all traces of it from the Vivox buddy list.
- if(buddy->mInVivoxBuddies)
- {
- // delete this entry from the vivox buddy list
- buddy->mInVivoxBuddies = false;
- LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.BuddyDelete.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "</Request>nnn";
- }
- if(buddy->mHasBlockListEntry)
- {
- // Delete the associated block list entry, if any
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteBlockRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>nnn";
- }
- if(buddy->mHasAutoAcceptListEntry)
- {
- // Delete the associated auto-accept list entry, if any
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteAutoAcceptRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>nnn";
- }
- }
-
- if(buddy->mInSLFriends)
- {
- if(buddy->mCanSeeMeOnline)
- {
- // Buddy should not be blocked.
- // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
-
- // If the buddy has a block list entry, delete it.
- if(buddy->mHasBlockListEntry)
- {
- buddy->mHasBlockListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteBlockRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "</Request>nnn";
-
-
- // If we just deleted a block list entry, add an auto-accept entry.
- if(!buddy->mHasAutoAcceptListEntry)
- {
- buddy->mHasAutoAcceptListEntry = true;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.CreateAutoAcceptRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "<AutoAddAsBuddy>0</AutoAddAsBuddy>"
- << "</Request>nnn";
- }
- }
- }
- else
- {
- // Buddy should be blocked.
-
- // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent.
- // If this buddy has an autoaccept entry, delete it
- if(buddy->mHasAutoAcceptListEntry)
- {
- buddy->mHasAutoAcceptListEntry = false;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.DeleteAutoAcceptRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<AutoAcceptMask>" << buddy->mURI << "</AutoAcceptMask>"
- << "</Request>nnn";
-
- // If we just deleted an auto-accept entry, add a block list entry.
- if(!buddy->mHasBlockListEntry)
- {
- buddy->mHasBlockListEntry = true;
- stream << "<Request requestId="" << mCommandCookie++ << "" action="Account.CreateBlockRule.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BlockMask>" << buddy->mURI << "</BlockMask>"
- << "<PresenceOnly>1</PresenceOnly>"
- << "</Request>nnn";
- }
- }
- }
- if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies)
- {
- // Delete this entry from the local buddy list. This should NOT invalidate the iterator,
- // since it has already been incremented to the next entry.
- deleteBuddy(buddy->mURI);
- }
- }
- writeString(stream.str());
- }
- }
- }
- }
- /////////////////////////////
- // Response/Event handlers
- void LLVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)
- {
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL;
- setState(stateConnectorFailed);
- }
- else
- {
- // Connector created, move forward.
- LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL;
- mAPIVersion = versionID;
- mConnectorHandle = connectorHandle;
- if(getState() == stateConnectorStarting)
- {
- setState(stateConnectorStarted);
- }
- }
- }
- void LLVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)
- {
- LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;
-
- // Status code of 20200 means "bad password". We may want to special-case that at some point.
-
- if ( statusCode == 401 )
- {
- // Login failure which is probably caused by the delay after a user's password being updated.
- LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- setState(stateLoginRetry);
- }
- else if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
- setState(stateLoginFailed);
- }
- else
- {
- // Login succeeded, move forward.
- mAccountHandle = accountHandle;
- mNumberOfAliases = numberOfAliases;
- // This needs to wait until the AccountLoginStateChangeEvent is received.
- // if(getState() == stateLoggingIn)
- // {
- // setState(stateLoggedIn);
- // }
- }
- }
- void LLVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
- {
- sessionState *session = findSessionBeingCreatedByURI(requestId);
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Create response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- setState(stateJoinSessionFailed);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_INFOS("Voice") << "Session.Create response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- }
- }
- void LLVoiceClient::sessionGroupAddSessionResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle)
- {
- sessionState *session = findSessionBeingCreatedByURI(requestId);
-
- if(session)
- {
- session->mCreateInProgress = false;
- }
-
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "SessionGroup.AddSession response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- {
- setState(stateJoinSessionFailed);
- }
- else
- {
- reapSession(session);
- }
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "SessionGroup.AddSession response received (success), session handle is " << sessionHandle << LL_ENDL;
- if(session)
- {
- setSessionHandle(session, sessionHandle);
- }
- }
- }
- void LLVoiceClient::sessionConnectResponse(std::string &requestId, int statusCode, std::string &statusString)
- {
- sessionState *session = findSession(requestId);
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Session.Connect response failure (" << statusCode << "): " << statusString << LL_ENDL;
- if(session)
- {
- session->mMediaConnectInProgress = false;
- session->mErrorStatusCode = statusCode;
- session->mErrorStatusString = statusString;
- if(session == mAudioSession)
- setState(stateJoinSessionFailed);
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session.Connect response received (success)" << LL_ENDL;
- }
- }
- void LLVoiceClient::logoutResponse(int statusCode, std::string &statusString)
- {
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
- }
- void LLVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
- {
- if(statusCode != 0)
- {
- LL_WARNS("Voice") << "Connector.InitiateShutdown response failure: " << statusString << LL_ENDL;
- // Should this ever fail? do we care if it does?
- }
-
- mConnected = false;
-
- if(getState() == stateConnectorStopping)
- {
- setState(stateConnectorStopped);
- }
- }
- void LLVoiceClient::sessionAddedEvent(
- std::string &uriString,
- std::string &alias,
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool isChannel,
- bool incoming,
- std::string &nameString,
- std::string &applicationString)
- {
- sessionState *session = NULL;
- LL_INFOS("Voice") << "session " << uriString << ", alias " << alias << ", name " << nameString << " handle " << sessionHandle << LL_ENDL;
-
- session = addSession(uriString, sessionHandle);
- if(session)
- {
- session->mGroupHandle = sessionGroupHandle;
- session->mIsChannel = isChannel;
- session->mIncoming = incoming;
- session->mAlias = alias;
-
- // Generate a caller UUID -- don't need to do this for channels
- if(!session->mIsChannel)
- {
- if(IDFromName(session->mSIPURI, session->mCallerID))
- {
- // Normal URI(base64-encoded UUID)
- }
- else if(!session->mAlias.empty() && IDFromName(session->mAlias, session->mCallerID))
- {
- // Wrong URI, but an alias is available. Stash the incoming URI as an alternate
- session->mAlternateSIPURI = session->mSIPURI;
-
- // and generate a proper URI from the ID.
- setSessionURI(session, sipURIFromID(session->mCallerID));
- }
- else
- {
- LL_INFOS("Voice") << "Could not generate caller id from uri, using hash of uri " << session->mSIPURI << LL_ENDL;
- setUUIDFromStringHash(session->mCallerID, session->mSIPURI);
- session->mSynthesizedCallerID = true;
-
- // Can't look up the name in this case -- we have to extract it from the URI.
- std::string namePortion = nameFromsipURI(session->mSIPURI);
- if(namePortion.empty())
- {
- // Didn't seem to be a SIP URI, just use the whole provided name.
- namePortion = nameString;
- }
-
- // Some incoming names may be separated with an underscore instead of a space. Fix this.
- LLStringUtil::replaceChar(namePortion, '_', ' ');
-
- // Act like we just finished resolving the name (this stores it in all the right places)
- avatarNameResolved(session->mCallerID, namePortion);
- }
-
- LL_INFOS("Voice") << "caller ID: " << session->mCallerID << LL_ENDL;
- if(!session->mSynthesizedCallerID)
- {
- // If we got here, we don't have a proper name. Initiate a lookup.
- lookupName(session->mCallerID);
- }
- }
- }
- }
- void LLVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)
- {
- LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL;
-
- #if USE_SESSION_GROUPS
- if(mMainSessionGroupHandle.empty())
- {
- // This is the first (i.e. "main") session group. Save its handle.
- mMainSessionGroupHandle = sessionGroupHandle;
- }
- else
- {
- LL_DEBUGS("Voice") << "Already had a session group handle " << mMainSessionGroupHandle << LL_ENDL;
- }
- #endif
- }
- void LLVoiceClient::joinedAudioSession(sessionState *session)
- {
- if(mAudioSession != session)
- {
- sessionState *oldSession = mAudioSession;
- mAudioSession = session;
- mAudioSessionChanged = true;
- // The old session may now need to be deleted.
- reapSession(oldSession);
- }
-
- // This is the session we're joining.
- if(getState() == stateJoiningSession)
- {
- setState(stateSessionJoined);
-
- // SLIM SDK: we don't always receive a participant state change for ourselves when joining a channel now.
- // Add the current user as a participant here.
- participantState *participant = session->addParticipant(sipURIFromName(mAccountName));
- if(participant)
- {
- participant->mIsSelf = true;
- lookupName(participant->mAvatarID);
- LL_INFOS("Voice") << "added self as participant "" << participant->mAccountName
- << "" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
-
- if(!session->mIsChannel)
- {
- // this is a p2p session. Make sure the other end is added as a participant.
- participantState *participant = session->addParticipant(session->mSIPURI);
- if(participant)
- {
- if(participant->mAvatarIDValid)
- {
- lookupName(participant->mAvatarID);
- }
- else if(!session->mName.empty())
- {
- participant->mDisplayName = session->mName;
- avatarNameResolved(participant->mAvatarID, session->mName);
- }
-
- // TODO: Question: Do we need to set up mAvatarID/mAvatarIDValid here?
- LL_INFOS("Voice") << "added caller as participant "" << participant->mAccountName
- << "" (" << participant->mAvatarID << ")"<< LL_ENDL;
- }
- }
- }
- }
- void LLVoiceClient::sessionRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle)
- {
- LL_INFOS("Voice") << "handle " << sessionHandle << LL_ENDL;
-
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- leftAudioSession(session);
- // This message invalidates the session's handle. Set it to empty.
- setSessionHandle(session);
-
- // This also means that the session's session group is now empty.
- // Terminate the session group so it doesn't leak.
- sessionGroupTerminateSendMessage(session);
-
- // Reset the media state (we now have no info)
- session->mMediaStreamState = streamStateUnknown;
- session->mTextStreamState = streamStateUnknown;
-
- // Conditionally delete the session
- reapSession(session);
- }
- else
- {
- LL_WARNS("Voice") << "unknown session " << sessionHandle << " removed" << LL_ENDL;
- }
- }
- void LLVoiceClient::reapSession(sessionState *session)
- {
- if(session)
- {
- if(!session->mHandle.empty())
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (non-null session handle)" << LL_ENDL;
- }
- else if(session->mCreateInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (create in progress)" << LL_ENDL;
- }
- else if(session->mMediaConnectInProgress)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (connect in progress)" << LL_ENDL;
- }
- else if(session == mAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the current session)" << LL_ENDL;
- }
- else if(session == mNextAudioSession)
- {
- LL_DEBUGS("Voice") << "NOT deleting session " << session->mSIPURI << " (it's the next session)" << LL_ENDL;
- }
- else
- {
- // TODO: Question: Should we check for queued text messages here?
- // We don't have a reason to keep tracking this session, so just delete it.
- LL_DEBUGS("Voice") << "deleting session " << session->mSIPURI << LL_ENDL;
- deleteSession(session);
- session = NULL;
- }
- }
- else
- {
- // LL_DEBUGS("Voice") << "session is NULL" << LL_ENDL;
- }
- }
- // Returns true if the session seems to indicate we've moved to a region on a different voice server
- bool LLVoiceClient::sessionNeedsRelog(sessionState *session)
- {
- bool result = false;
-
- if(session != NULL)
- {
- // Only make this check for spatial channels (so it won't happen for group or p2p calls)
- if(session->mIsSpatial)
- {
- std::string::size_type atsign;
-
- atsign = session->mSIPURI.find("@");
-
- if(atsign != std::string::npos)
- {
- std::string urihost = session->mSIPURI.substr(atsign + 1);
- if(stricmp(urihost.c_str(), mVoiceSIPURIHostName.c_str()))
- {
- // The hostname in this URI is different from what we expect. This probably means we need to relog.
-
- // We could make a ProvisionVoiceAccountRequest and compare the result with the current values of
- // mVoiceSIPURIHostName and mVoiceAccountServerURI to be really sure, but this is a pretty good indicator.
-
- result = true;
- }
- }
- }
- }
-
- return result;
- }
- void LLVoiceClient::leftAudioSession(
- sessionState *session)
- {
- if(mAudioSession == session)
- {
- switch(getState())
- {
- case stateJoiningSession:
- case stateSessionJoined:
- case stateRunning:
- case stateLeavingSession:
- case stateJoinSessionFailed:
- case stateJoinSessionFailedWaiting:
- // normal transition
- LL_DEBUGS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
- setState(stateSessionTerminated);
- break;
-
- case stateSessionTerminated:
- // this will happen sometimes -- there are cases where we send the terminate and then go straight to this state.
- LL_WARNS("Voice") << "left session " << session->mHandle << " in state " << state2string(getState()) << LL_ENDL;
- break;
-
- default:
- LL_WARNS("Voice") << "unexpected SessionStateChangeEvent (left session) in state " << state2string(getState()) << LL_ENDL;
- setState(stateSessionTerminated);
- break;
- }
- }
- }
- void LLVoiceClient::accountLoginStateChangeEvent(
- std::string &accountHandle,
- int statusCode,
- std::string &statusString,
- int state)
- {
- LL_DEBUGS("Voice") << "state is " << state << LL_ENDL;
- /*
- According to Mike S., status codes for this event are:
- login_state_logged_out=0,
- login_state_logged_in = 1,
- login_state_logging_in = 2,
- login_state_logging_out = 3,
- login_state_resetting = 4,
- login_state_error=100
- */
-
- switch(state)
- {
- case 1:
- if(getState() == stateLoggingIn)
- {
- setState(stateLoggedIn);
- }
- break;
- case 3:
- // The user is in the process of logging out.
- setState(stateLoggingOut);
- break;
- case 0:
- // The user has been logged out.
- setState(stateLoggedOut);
- break;
-
- default:
- //Used to be a commented out warning
- LL_DEBUGS("Voice") << "unknown state: " << state << LL_ENDL;
- break;
- }
- }
- void LLVoiceClient::mediaStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- int statusCode,
- std::string &statusString,
- int state,
- bool incoming)
- {
- sessionState *session = findSession(sessionHandle);
-
- LL_DEBUGS("Voice") << "session " << sessionHandle << ", status code " << statusCode << ", string "" << statusString << """ << LL_ENDL;
-
- if(session)
- {
- // We know about this session
-
- // Save the state for later use
- session->mMediaStreamState = state;
-
- switch(statusCode)
- {
- case 0:
- case 200:
- // generic success
- // Don't change the saved error code (it may have been set elsewhere)
- break;
- default:
- // save the status code for later
- session->mErrorStatusCode = statusCode;
- break;
- }
-
- switch(state)
- {
- case streamStateIdle:
- // Standard "left audio session"
- session->mVoiceEnabled = false;
- session->mMediaConnectInProgress = false;
- leftAudioSession(session);
- break;
- case streamStateConnected:
- session->mVoiceEnabled = true;
- session->mMediaConnectInProgress = false;
- joinedAudioSession(session);
- break;
-
- case streamStateRinging:
- if(incoming)
- {
- // Send the voice chat invite to the GUI layer
- // *TODO: Question: Should we correlate with the mute list here?
- session->mIMSessionID = LLIMMgr::computeSessionID(IM_SESSION_P2P_INVITE, session->mCallerID);
- session->mVoiceInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- }
- break;
-
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
-
- }
- else
- {
- LL_WARNS("Voice") << "session " << sessionHandle << "not found"<< LL_ENDL;
- }
- }
- void LLVoiceClient::textStreamUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- bool enabled,
- int state,
- bool incoming)
- {
- sessionState *session = findSession(sessionHandle);
-
- if(session)
- {
- // Save the state for later use
- session->mTextStreamState = state;
-
- // We know about this session
- switch(state)
- {
- case 0: // We see this when the text stream closes
- LL_DEBUGS("Voice") << "stream closed" << LL_ENDL;
- break;
-
- case 1: // We see this on an incoming call from the Connector
- // Try to send any text messages queued for this session.
- sendQueuedTextMessages(session);
- // Send the text chat invite to the GUI layer
- // TODO: Question: Should we correlate with the mute list here?
- session->mTextInvitePending = true;
- if(session->mName.empty())
- {
- lookupName(session->mCallerID);
- }
- else
- {
- // Act like we just finished resolving the name
- avatarNameResolved(session->mCallerID, session->mName);
- }
- break;
- default:
- LL_WARNS("Voice") << "unknown state " << state << LL_ENDL;
- break;
-
- }
- }
- }
- void LLVoiceClient::participantAddedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString,
- std::string &displayNameString,
- int participantType)
- {
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- participantState *participant = session->addParticipant(uriString);
- if(participant)
- {
- participant->mAccountName = nameString;
- LL_DEBUGS("Voice") << "added participant "" << participant->mAccountName
- << "" (" << participant->mAvatarID << ")"<< LL_ENDL;
- if(participant->mAvatarIDValid)
- {
- // Initiate a lookup
- lookupName(participant->mAvatarID);
- }
- else
- {
- // If we don't have a valid avatar UUID, we need to fill in the display name to make the active speakers floater work.
- std::string namePortion = nameFromsipURI(uriString);
- if(namePortion.empty())
- {
- // Problem with the SIP URI, fall back to the display name
- namePortion = displayNameString;
- }
- if(namePortion.empty())
- {
- // Problems with both of the above, fall back to the account name
- namePortion = nameString;
- }
-
- // Set the display name (which is a hint to the active speakers window not to do its own lookup)
- participant->mDisplayName = namePortion;
- avatarNameResolved(participant->mAvatarID, namePortion);
- }
- }
- }
- }
- void LLVoiceClient::participantRemovedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- std::string &nameString)
- {
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- participantState *participant = session->findParticipant(uriString);
- if(participant)
- {
- session->removeParticipant(participant);
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
- }
- void LLVoiceClient::participantUpdatedEvent(
- std::string &sessionHandle,
- std::string &sessionGroupHandle,
- std::string &uriString,
- std::string &alias,
- bool isModeratorMuted,
- bool isSpeaking,
- int volume,
- F32 energy)
- {
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- participantState *participant = session->findParticipant(uriString);
-
- if(participant)
- {
- participant->mIsSpeaking = isSpeaking;
- participant->mIsModeratorMuted = isModeratorMuted;
- // SLIM SDK: convert range: ensure that energy is set to zero if is_speaking is false
- if (isSpeaking)
- {
- participant->mSpeakingTimeout.reset();
- participant->mPower = energy;
- }
- else
- {
- participant->mPower = 0.0f;
- }
- participant->mVolume = volume;
-
- // *HACK: mantipov: added while working on EXT-3544
- /*
- Sometimes LLVoiceClient::participantUpdatedEvent callback is called BEFORE
- LLViewerChatterBoxSessionAgentListUpdates::post() sometimes AFTER.
-
- participantUpdatedEvent updates voice participant state in particular participantState::mIsModeratorMuted
- Originally we wanted to update session Speaker Manager to fire LLSpeakerVoiceModerationEvent to fix the EXT-3544 bug.
- Calling of the LLSpeakerMgr::update() method was added into LLIMMgr::processAgentListUpdates.
-
- But in case participantUpdatedEvent() is called after LLViewerChatterBoxSessionAgentListUpdates::post()
- voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager
- and event is not fired.
- So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it
- in LLCallFloater::draw()
- */
- LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel();
- // ignore session ID of local chat
- if (voice_cnl && voice_cnl->getSessionID().notNull())
- {
- LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(voice_cnl->getSessionID());
- if (speaker_manager)
- {
- speaker_manager->update(true);
- }
- }
- }
- else
- {
- LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL;
- }
- }
- else
- {
- LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL;
- }
- }
- void LLVoiceClient::buddyPresenceEvent(
- std::string &uriString,
- std::string &alias,
- std::string &statusString,
- std::string &applicationString)
- {
- buddyListEntry *buddy = findBuddy(uriString);
-
- if(buddy)
- {
- LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status "" << statusString << "", application "" << applicationString << """<< LL_ENDL;
- LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
- if(applicationString.empty())
- {
- // This presence event is from a client that doesn't set up the Application string. Do things the old-skool way.
- // NOTE: this will be needed to support people who aren't on the 3010-class SDK yet.
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // User went offline with a non-SLim-enabled viewer.
- buddy->mOnlineSL = false;
- }
- else if ( stricmp("Online", statusString.c_str())== 0)
- {
- // User came online with a non-SLim-enabled viewer.
- buddy->mOnlineSL = true;
- }
- else
- {
- // If the user is online through SLim, their status will be "Online-slc", "Away", or something else.
- // NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string.
- buddy->mOnlineSLim = true;
- }
- }
- else if(applicationString.find("SecondLifeViewer") != std::string::npos)
- {
- // This presence event is from a viewer that sets the application string
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // Viewer says they're offline
- buddy->mOnlineSL = false;
- }
- else
- {
- // Viewer says they're online
- buddy->mOnlineSL = true;
- }
- }
- else
- {
- // This presence event is from something which is NOT the SL viewer (assume it's SLim).
- if ( stricmp("Unknown", statusString.c_str())== 0)
- {
- // SLim says they're offline
- buddy->mOnlineSLim = false;
- }
- else
- {
- // SLim says they're online
- buddy->mOnlineSLim = true;
- }
- }
- LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL;
-
- // HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change.
- LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID));
- notifyFriendObservers();
- }
- else
- {
- LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL;
- }
- }
- void LLVoiceClient::messageEvent(
- std::string &sessionHandle,
- std::string &uriString,
- std::string &alias,
- std::string &messageHeader,
- std::string &messageBody,
- std::string &applicationString)
- {
- LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
- // LL_DEBUGS("Voice") << " header " << messageHeader << ", body: n" << messageBody << LL_ENDL;
-
- if(messageHeader.find("text/html") != std::string::npos)
- {
- std::string message;
- {
- const std::string startMarker = "<body";
- const std::string startMarker2 = ">";
- const std::string endMarker = "</body>";
- const std::string startSpan = "<span";
- const std::string endSpan = "</span>";
- std::string::size_type start;
- std::string::size_type end;
-
- // Default to displaying the raw string, so the message gets through.
- message = messageBody;
- // Find the actual message text within the XML fragment
- start = messageBody.find(startMarker);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endMarker);
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- else
- {
- // Didn't find a <body>, try looking for a <span> instead.
- start = messageBody.find(startSpan);
- start = messageBody.find(startMarker2, start);
- end = messageBody.find(endSpan);
-
- if(start != std::string::npos)
- {
- start += startMarker2.size();
-
- if(end != std::string::npos)
- end -= start;
-
- message.assign(messageBody, start, end);
- }
- }
- }
-
- // LL_DEBUGS("Voice") << " raw message = n" << message << LL_ENDL;
- // strip formatting tags
- {
- std::string::size_type start;
- std::string::size_type end;
-
- while((start = message.find('<')) != std::string::npos)
- {
- if((end = message.find('>', start + 1)) != std::string::npos)
- {
- // Strip out the tag
- message.erase(start, (end + 1) - start);
- }
- else
- {
- // Avoid an infinite loop
- break;
- }
- }
- }
-
- // Decode ampersand-escaped chars
- {
- std::string::size_type mark = 0;
- // The text may contain text encoded with <, >, and &
- mark = 0;
- while((mark = message.find("<", mark)) != std::string::npos)
- {
- message.replace(mark, 4, "<");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find(">", mark)) != std::string::npos)
- {
- message.replace(mark, 4, ">");
- mark += 1;
- }
-
- mark = 0;
- while((mark = message.find("&", mark)) != std::string::npos)
- {
- message.replace(mark, 5, "&");
- mark += 1;
- }
- }
-
- // strip leading/trailing whitespace (since we always seem to get a couple newlines)
- LLStringUtil::trim(message);
-
- // LL_DEBUGS("Voice") << " stripped message = n" << message << LL_ENDL;
-
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- bool is_busy = gAgent.getBusy();
- bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat);
- bool is_linden = LLMuteList::getInstance()->isLinden(session->mName);
- bool quiet_chat = false;
- LLChat chat;
- chat.mMuted = is_muted && !is_linden;
-
- if(!chat.mMuted)
- {
- chat.mFromID = session->mCallerID;
- chat.mFromName = session->mName;
- chat.mSourceType = CHAT_SOURCE_AGENT;
- if(is_busy && !is_linden)
- {
- quiet_chat = true;
- // TODO: Question: Return busy mode response here? Or maybe when session is started instead?
- }
-
- LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
- gIMMgr->addMessage(session->mIMSessionID,
- session->mCallerID,
- session->mName.c_str(),
- message.c_str(),
- LLStringUtil::null, // default arg
- IM_NOTHING_SPECIAL, // default arg
- 0, // default arg
- LLUUID::null, // default arg
- LLVector3::zero, // default arg
- true); // prepend name and make it a link to the user's profile
- }
- }
- }
- }
- void LLVoiceClient::sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType)
- {
- sessionState *session = findSession(sessionHandle);
-
- if(session)
- {
- participantState *participant = session->findParticipant(uriString);
- if(participant)
- {
- if (!stricmp(notificationType.c_str(), "Typing"))
- {
- // Other end started typing
- // TODO: The proper way to add a typing notification seems to be LLIMMgr::processIMTypingStart().
- // It requires an LLIMInfo for the message, which we don't have here.
- }
- else if (!stricmp(notificationType.c_str(), "NotTyping"))
- {
- // Other end stopped typing
- // TODO: The proper way to remove a typing notification seems to be LLIMMgr::processIMTypingStop().
- // It requires an LLIMInfo for the message, which we don't have here.
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown notification type " << notificationType << "for participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown participant " << uriString << " in session " << session->mSIPURI << LL_ENDL;
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Unknown session handle " << sessionHandle << LL_ENDL;
- }
- }
- void LLVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType)
- {
- buddyListEntry *buddy = findBuddy(buddyURI);
-
- if(!buddy)
- {
- // Couldn't find buddy by URI, try converting the alias...
- if(!alias.empty())
- {
- LLUUID id;
- if(IDFromName(alias, id))
- {
- buddy = findBuddy(id);
- }
- }
- }
-
- if(buddy)
- {
- std::ostringstream stream;
-
- if(buddy->mCanSeeMeOnline)
- {
- // Sending the response will create an auto-accept rule
- buddy->mHasAutoAcceptListEntry = true;
- }
- else
- {
- // Sending the response will create a block rule
- buddy->mHasBlockListEntry = true;
- }
-
- if(buddy->mInSLFriends)
- {
- buddy->mInVivoxBuddies = true;
- }
-
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="Account.SendSubscriptionReply.1">"
- << "<AccountHandle>" << mAccountHandle << "</AccountHandle>"
- << "<BuddyURI>" << buddy->mURI << "</BuddyURI>"
- << "<RuleType>" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "</RuleType>"
- << "<AutoAccept>"<< (buddy->mInSLFriends?"1":"0")<< "</AutoAccept>"
- << "<SubscriptionHandle>" << subscriptionHandle << "</SubscriptionHandle>"
- << "</Request>"
- << "nnn";
-
- writeString(stream.str());
- }
- }
- void LLVoiceClient::auxAudioPropertiesEvent(F32 energy)
- {
- LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL;
- mTuningEnergy = energy;
- }
- void LLVoiceClient::buddyListChanged()
- {
- // This is called after we receive a BuddyAndGroupListChangedEvent.
- mBuddyListMapPopulated = true;
- mFriendsListDirty = true;
- }
- void LLVoiceClient::muteListChanged()
- {
- // The user's mute list has been updated. Go through the current participant list and sync it with the mute list.
- if(mAudioSession)
- {
- participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
-
- for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
- {
- participantState *p = iter->second;
-
- // Check to see if this participant is on the mute list already
- if(p->updateMuteState())
- mAudioSession->mVolumeDirty = true;
- }
- }
- }
- void LLVoiceClient::updateFriends(U32 mask)
- {
- if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS))
- {
- // Just resend the whole friend list to the daemon
- mFriendsListDirty = true;
- }
- }
- /////////////////////////////
- // Managing list of participants
- LLVoiceClient::participantState::participantState(const std::string &uri) :
- mURI(uri),
- mPTT(false),
- mIsSpeaking(false),
- mIsModeratorMuted(false),
- mLastSpokeTimestamp(0.f),
- mPower(0.f),
- mVolume(-1),
- mOnMuteList(false),
- mUserVolume(-1),
- mVolumeDirty(false),
- mAvatarIDValid(false),
- mIsSelf(false)
- {
- }
- LLVoiceClient::participantState *LLVoiceClient::sessionState::addParticipant(const std::string &uri)
- {
- participantState *result = NULL;
- bool useAlternateURI = false;
-
- // Note: this is mostly the body of LLVoiceClient::sessionState::findParticipant(), but since we need to know if it
- // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here.
- {
- participantMap::iterator iter = mParticipantsByURI.find(&uri);
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Use mSIPURI instead, since it will be properly encoded.
- iter = mParticipantsByURI.find(&(mSIPURI));
- useAlternateURI = true;
- }
- }
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
- }
-
- if(!result)
- {
- // participant isn't already in one list or the other.
- result = new participantState(useAlternateURI?mSIPURI:uri);
- mParticipantsByURI.insert(participantMap::value_type(&(result->mURI), result));
- mParticipantsChanged = true;
-
- // Try to do a reverse transform on the URI to get the GUID back.
- {
- LLUUID id;
- if(IDFromName(result->mURI, id))
- {
- result->mAvatarIDValid = true;
- result->mAvatarID = id;
- if(result->updateMuteState())
- mVolumeDirty = true;
- }
- else
- {
- // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid.
- // This tells both code in LLVoiceClient and code in llfloateractivespeakers.cpp that the ID will not be in the name cache.
- setUUIDFromStringHash(result->mAvatarID, uri);
- }
- }
-
- mParticipantsByUUID.insert(participantUUIDMap::value_type(&(result->mAvatarID), result));
- result->mUserVolume = LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID);
- if (result->mUserVolume != -1)
- {
- result->mVolumeDirty = true;
- mVolumeDirty = true;
- }
- LL_DEBUGS("Voice") << "participant "" << result->mURI << "" added." << LL_ENDL;
- }
-
- return result;
- }
- bool LLVoiceClient::participantState::updateMuteState()
- {
- bool result = false;
-
- if(mAvatarIDValid)
- {
- bool isMuted = LLMuteList::getInstance()->isMuted(mAvatarID, LLMute::flagVoiceChat);
- if(mOnMuteList != isMuted)
- {
- mOnMuteList = isMuted;
- mVolumeDirty = true;
- result = true;
- }
- }
- return result;
- }
- bool LLVoiceClient::participantState::isAvatar()
- {
- return mAvatarIDValid;
- }
- void LLVoiceClient::sessionState::removeParticipant(LLVoiceClient::participantState *participant)
- {
- if(participant)
- {
- participantMap::iterator iter = mParticipantsByURI.find(&(participant->mURI));
- participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(&(participant->mAvatarID));
-
- LL_DEBUGS("Voice") << "participant "" << participant->mURI << "" (" << participant->mAvatarID << ") removed." << LL_ENDL;
-
- if(iter == mParticipantsByURI.end())
- {
- LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL;
- }
- else if(iter2 == mParticipantsByUUID.end())
- {
- LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL;
- }
- else if(iter->second != iter2->second)
- {
- LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL;
- }
- else
- {
- mParticipantsByURI.erase(iter);
- mParticipantsByUUID.erase(iter2);
-
- delete participant;
- mParticipantsChanged = true;
- }
- }
- }
- void LLVoiceClient::sessionState::removeAllParticipants()
- {
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- while(!mParticipantsByURI.empty())
- {
- removeParticipant(mParticipantsByURI.begin()->second);
- }
-
- if(!mParticipantsByUUID.empty())
- {
- LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL;
- }
- }
- LLVoiceClient::participantMap *LLVoiceClient::getParticipantList(void)
- {
- participantMap *result = NULL;
- if(mAudioSession)
- {
- result = &(mAudioSession->mParticipantsByURI);
- }
- return result;
- }
- void LLVoiceClient::getParticipantsUUIDSet(std::set<LLUUID>& participant_uuids)
- {
- if (NULL == mAudioSession) return;
- participantUUIDMap::const_iterator it = mAudioSession->mParticipantsByUUID.begin(),
- it_end = mAudioSession->mParticipantsByUUID.end();
- for (; it != it_end; ++it)
- {
- participant_uuids.insert((*(*it).first));
- }
- }
- LLVoiceClient::participantState *LLVoiceClient::sessionState::findParticipant(const std::string &uri)
- {
- participantState *result = NULL;
-
- participantMap::iterator iter = mParticipantsByURI.find(&uri);
- if(iter == mParticipantsByURI.end())
- {
- if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI))
- {
- // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant.
- // Look up the other URI
- iter = mParticipantsByURI.find(&(mSIPURI));
- }
- }
- if(iter != mParticipantsByURI.end())
- {
- result = iter->second;
- }
-
- return result;
- }
- LLVoiceClient::participantState* LLVoiceClient::sessionState::findParticipantByID(const LLUUID& id)
- {
- participantState * result = NULL;
- participantUUIDMap::iterator iter = mParticipantsByUUID.find(&id);
- if(iter != mParticipantsByUUID.end())
- {
- result = iter->second;
- }
- return result;
- }
- LLVoiceClient::participantState* LLVoiceClient::findParticipantByID(const LLUUID& id)
- {
- participantState * result = NULL;
-
- if(mAudioSession)
- {
- result = mAudioSession->findParticipantByID(id);
- }
-
- return result;
- }
- void LLVoiceClient::parcelChanged()
- {
- if(getState() >= stateNoChannel)
- {
- // If the user is logged in, start a channel lookup.
- LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
- std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
- LLSD data;
- LLHTTPClient::post(
- url,
- data,
- new LLVoiceClientCapResponder);
- }
- else
- {
- // The transition to stateNoChannel needs to kick this off again.
- LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL;
- }
- }
- void LLVoiceClient::switchChannel(
- std::string uri,
- bool spatial,
- bool no_reconnect,
- bool is_p2p,
- std::string hash)
- {
- bool needsSwitch = false;
-
- LL_DEBUGS("Voice")
- << "called in state " << state2string(getState())
- << " with uri "" << uri << """
- << (spatial?", spatial is true":", spatial is false")
- << LL_ENDL;
-
- switch(getState())
- {
- case stateJoinSessionFailed:
- case stateJoinSessionFailedWaiting:
- case stateNoChannel:
- // Always switch to the new URI from these states.
- needsSwitch = true;
- break;
- default:
- if(mSessionTerminateRequested)
- {
- // If a terminate has been requested, we need to compare against where the URI we're already headed to.
- if(mNextAudioSession)
- {
- if(mNextAudioSession->mSIPURI != uri)
- needsSwitch = true;
- }
- else
- {
- // mNextAudioSession is null -- this probably means we're on our way back to spatial.
- if(!uri.empty())
- {
- // We do want to process a switch in this case.
- needsSwitch = true;
- }
- }
- }
- else
- {
- // Otherwise, compare against the URI we're in now.
- if(mAudioSession)
- {
- if(mAudioSession->mSIPURI != uri)
- {
- needsSwitch = true;
- }
- }
- else
- {
- if(!uri.empty())
- {
- // mAudioSession is null -- it's not clear what case would cause this.
- // For now, log it as a warning and see if it ever crops up.
- LL_WARNS("Voice") << "No current audio session." << LL_ENDL;
- }
- }
- }
- break;
- }
-
- if(needsSwitch)
- {
- if(uri.empty())
- {
- // Leave any channel we may be in
- LL_DEBUGS("Voice") << "leaving channel" << LL_ENDL;
- sessionState *oldSession = mNextAudioSession;
- mNextAudioSession = NULL;
- // The old session may now need to be deleted.
- reapSession(oldSession);
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- }
- else
- {
- LL_DEBUGS("Voice") << "switching to channel " << uri << LL_ENDL;
- mNextAudioSession = addSession(uri);
- mNextAudioSession->mHash = hash;
- mNextAudioSession->mIsSpatial = spatial;
- mNextAudioSession->mReconnect = !no_reconnect;
- mNextAudioSession->mIsP2P = is_p2p;
- }
-
- if(getState() <= stateNoChannel)
- {
- // We're already set up to join a channel, just needed to fill in the session URI
- }
- else
- {
- // State machine will come around and rejoin if uri/handle is not empty.
- sessionTerminate();
- }
- }
- }
- void LLVoiceClient::joinSession(sessionState *session)
- {
- mNextAudioSession = session;
-
- if(getState() <= stateNoChannel)
- {
- // We're already set up to join a channel, just needed to fill in the session handle
- }
- else
- {
- // State machine will come around and rejoin if uri/handle is not empty.
- sessionTerminate();
- }
- }
- void LLVoiceClient::setNonSpatialChannel(
- const std::string &uri,
- const std::string &credentials)
- {
- switchChannel(uri, false, false, false, credentials);
- }
- void LLVoiceClient::setSpatialChannel(
- const std::string &uri,
- const std::string &credentials)
- {
- mSpatialSessionURI = uri;
- mSpatialSessionCredentials = credentials;
- mAreaVoiceDisabled = mSpatialSessionURI.empty();
- LL_DEBUGS("Voice") << "got spatial channel uri: "" << uri << """ << LL_ENDL;
-
- if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial)))
- {
- // User is in a non-spatial chat or joining a non-spatial chat. Don't switch channels.
- LL_INFOS("Voice") << "in non-spatial chat, not switching channels" << LL_ENDL;
- }
- else
- {
- switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
- }
- void LLVoiceClient::callUser(const LLUUID &uuid)
- {
- std::string userURI = sipURIFromID(uuid);
- switchChannel(userURI, false, true, true);
- }
- LLVoiceClient::sessionState* LLVoiceClient::startUserIMSession(const LLUUID &uuid)
- {
- // Figure out if a session with the user already exists
- sessionState *session = findSession(uuid);
- if(!session)
- {
- // No session with user, need to start one.
- std::string uri = sipURIFromID(uuid);
- session = addSession(uri);
- llassert(session);
- if (!session) return NULL;
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
- session->mCallerID = uuid;
- }
-
- if(session->mHandle.empty())
- {
- // Session isn't active -- start it up.
- sessionCreateSendMessage(session, false, true);
- }
- else
- {
- // Session is already active -- start up text.
- sessionTextConnectSendMessage(session);
- }
-
- return session;
- }
- bool LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
- {
- bool result = false;
- // Attempt to locate the indicated session
- sessionState *session = startUserIMSession(participant_id);
- if(session)
- {
- // found the session, attempt to send the message
- session->mTextMsgQueue.push(message);
-
- // Try to send queued messages (will do nothing if the session is not open yet)
- sendQueuedTextMessages(session);
- // The message is queued, so we succeed.
- result = true;
- }
- else
- {
- LL_DEBUGS("Voice") << "Session not found for participant ID " << participant_id << LL_ENDL;
- }
-
- return result;
- }
- void LLVoiceClient::sendQueuedTextMessages(sessionState *session)
- {
- if(session->mTextStreamState == 1)
- {
- if(!session->mTextMsgQueue.empty())
- {
- std::ostringstream stream;
-
- while(!session->mTextMsgQueue.empty())
- {
- std::string message = session->mTextMsgQueue.front();
- session->mTextMsgQueue.pop();
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="Session.SendMessage.1">"
- << "<SessionHandle>" << session->mHandle << "</SessionHandle>"
- << "<MessageHeader>text/HTML</MessageHeader>"
- << "<MessageBody>" << message << "</MessageBody>"
- << "</Request>"
- << "nnn";
- }
- writeString(stream.str());
- }
- }
- else
- {
- // Session isn't connected yet, defer until later.
- }
- }
- void LLVoiceClient::endUserIMSession(const LLUUID &uuid)
- {
- // Figure out if a session with the user exists
- sessionState *session = findSession(uuid);
- if(session)
- {
- // found the session
- if(!session->mHandle.empty())
- {
- sessionTextDisconnectSendMessage(session);
- }
- }
- else
- {
- LL_DEBUGS("Voice") << "Session not found for participant ID " << uuid << LL_ENDL;
- }
- }
- bool LLVoiceClient::answerInvite(std::string &sessionHandle)
- {
- // this is only ever used to answer incoming p2p call invites.
-
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- session->mIsSpatial = false;
- session->mReconnect = false;
- session->mIsP2P = true;
- joinSession(session);
- return true;
- }
-
- return false;
- }
- bool LLVoiceClient::isOnlineSIP(const LLUUID &id)
- {
- bool result = false;
- buddyListEntry *buddy = findBuddy(id);
- if(buddy)
- {
- result = buddy->mOnlineSLim;
- LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL;
- }
- if(!result)
- {
- // This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM.
- sessionState *session = findSession(id);
- if(session && !session->mHandle.empty())
- {
- if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle))
- {
- LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL;
- // we have a p2p text session open with this user, so by definition they're online.
- result = true;
- }
- }
- }
-
- return result;
- }
- // Returns true if the indicated participant in the current audio session is really an SL avatar.
- // Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
- bool LLVoiceClient::isParticipantAvatar(const LLUUID &id)
- {
- bool result = true;
- sessionState *session = findSession(id);
-
- if(session != NULL)
- {
- // this is a p2p session with the indicated caller, or the session with the specified UUID.
- if(session->mSynthesizedCallerID)
- result = false;
- }
- else
- {
- // Didn't find a matching session -- check the current audio session for a matching participant
- if(mAudioSession != NULL)
- {
- participantState *participant = findParticipantByID(id);
- if(participant != NULL)
- {
- result = participant->isAvatar();
- }
- }
- }
-
- return result;
- }
- // 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.
- bool LLVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
- {
- bool result = true;
- sessionState *session = findSession(session_id);
-
- if(session != NULL)
- {
- result = session->isCallBackPossible();
- }
-
- return result;
- }
- // Returns true if the session can accepte text IM's.
- // Currently this will be false only for PSTN P2P calls.
- bool LLVoiceClient::isSessionTextIMPossible(const LLUUID &session_id)
- {
- bool result = true;
- sessionState *session = findSession(session_id);
-
- if(session != NULL)
- {
- result = session->isTextIMPossible();
- }
-
- return result;
- }
-
- void LLVoiceClient::declineInvite(std::string &sessionHandle)
- {
- sessionState *session = findSession(sessionHandle);
- if(session)
- {
- sessionMediaDisconnectSendMessage(session);
- }
- }
- void LLVoiceClient::leaveNonSpatialChannel()
- {
- LL_DEBUGS("Voice")
- << "called in state " << state2string(getState())
- << LL_ENDL;
-
- // Make sure we don't rejoin the current session.
- sessionState *oldNextSession = mNextAudioSession;
- mNextAudioSession = NULL;
-
- // Most likely this will still be the current session at this point, but check it anyway.
- reapSession(oldNextSession);
-
- verifySessionState();
-
- sessionTerminate();
- }
- std::string LLVoiceClient::getCurrentChannel()
- {
- std::string result;
-
- if((getState() == stateRunning) && !mSessionTerminateRequested)
- {
- result = getAudioSessionURI();
- }
-
- return result;
- }
- bool LLVoiceClient::inProximalChannel()
- {
- bool result = false;
-
- if((getState() == stateRunning) && !mSessionTerminateRequested)
- {
- result = inSpatialChannel();
- }
-
- return result;
- }
- std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
- {
- std::string result;
- result = "sip:";
- result += nameFromID(id);
- result += "@";
- result += mVoiceSIPURIHostName;
-
- return result;
- }
- std::string LLVoiceClient::sipURIFromAvatar(LLVOAvatar *avatar)
- {
- std::string result;
- if(avatar)
- {
- result = "sip:";
- result += nameFromID(avatar->getID());
- result += "@";
- result += mVoiceSIPURIHostName;
- }
-
- return result;
- }
- std::string LLVoiceClient::nameFromAvatar(LLVOAvatar *avatar)
- {
- std::string result;
- if(avatar)
- {
- result = nameFromID(avatar->getID());
- }
- return result;
- }
- std::string LLVoiceClient::nameFromID(const LLUUID &uuid)
- {
- std::string result;
-
- if (uuid.isNull()) {
- //VIVOX, the uuid emtpy look for the mURIString and return that instead.
- //result.assign(uuid.mURIStringName);
- LLStringUtil::replaceChar(result, '_', ' ');
- return result;
- }
- // Prepending this apparently prevents conflicts with reserved names inside the vivox and diamondware code.
- result = "x";
-
- // Base64 encode and replace the pieces of base64 that are less compatible
- // with e-mail local-parts.
- // See RFC-4648 "Base 64 Encoding with URL and Filename Safe Alphabet"
- result += LLBase64::encode(uuid.mData, UUID_BYTES);
- LLStringUtil::replaceChar(result, '+', '-');
- LLStringUtil::replaceChar(result, '/', '_');
-
- // If you need to transform a GUID to this form on the Mac OS X command line, this will do so:
- // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
-
- // The reverse transform can be done with:
- // echo 'x5mkTKmxDTuGnjWyC__WfMg==' |cut -b 2- -|tr '_-' '/+' |openssl base64 -d|xxd -p
-
- return result;
- }
- bool LLVoiceClient::IDFromName(const std::string inName, LLUUID &uuid)
- {
- bool result = false;
-
- // SLIM SDK: The "name" may actually be a SIP URI such as: "sip:xFnPP04IpREWNkuw1cOXlhw==@bhr.vivox.com"
- // If it is, convert to a bare name before doing the transform.
- std::string name = nameFromsipURI(inName);
-
- // Doesn't look like a SIP URI, assume it's an actual name.
- if(name.empty())
- name = inName;
- // This will only work if the name is of the proper form.
- // As an example, the account name for Monroe Linden (UUID 1673cfd3-8229-4445-8d92-ec3570e5e587) is:
- // "xFnPP04IpREWNkuw1cOXlhw=="
-
- if((name.size() == 25) && (name[0] == 'x') && (name[23] == '=') && (name[24] == '='))
- {
- // The name appears to have the right form.
- // Reverse the transforms done by nameFromID
- std::string temp = name;
- LLStringUtil::replaceChar(temp, '-', '+');
- LLStringUtil::replaceChar(temp, '_', '/');
- U8 rawuuid[UUID_BYTES + 1];
- int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1);
- if(len == UUID_BYTES)
- {
- // The decode succeeded. Stuff the bits into the result's UUID
- memcpy(uuid.mData, rawuuid, UUID_BYTES);
- result = true;
- }
- }
-
- if(!result)
- {
- // VIVOX: not a standard account name, just copy the URI name mURIString field
- // and hope for the best. bpj
- uuid.setNull(); // VIVOX, set the uuid field to nulls
- }
-
- return result;
- }
- std::string LLVoiceClient::displayNameFromAvatar(LLVOAvatar *avatar)
- {
- return avatar->getFullname();
- }
- std::string LLVoiceClient::sipURIFromName(std::string &name)
- {
- std::string result;
- result = "sip:";
- result += name;
- result += "@";
- result += mVoiceSIPURIHostName;
- // LLStringUtil::toLower(result);
- return result;
- }
- std::string LLVoiceClient::nameFromsipURI(const std::string &uri)
- {
- std::string result;
- std::string::size_type sipOffset, atOffset;
- sipOffset = uri.find("sip:");
- atOffset = uri.find("@");
- if((sipOffset != std::string::npos) && (atOffset != std::string::npos))
- {
- result = uri.substr(sipOffset + 4, atOffset - (sipOffset + 4));
- }
-
- return result;
- }
- bool LLVoiceClient::inSpatialChannel(void)
- {
- bool result = false;
-
- if(mAudioSession)
- result = mAudioSession->mIsSpatial;
-
- return result;
- }
- std::string LLVoiceClient::getAudioSessionURI()
- {
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mSIPURI;
-
- return result;
- }
- std::string LLVoiceClient::getAudioSessionHandle()
- {
- std::string result;
-
- if(mAudioSession)
- result = mAudioSession->mHandle;
-
- return result;
- }
- /////////////////////////////
- // Sending updates of current state
- void LLVoiceClient::enforceTether(void)
- {
- LLVector3d tethered = mCameraRequestedPosition;
- // constrain 'tethered' to within 50m of mAvatarPosition.
- {
- F32 max_dist = 50.0f;
- LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
- F32 camera_distance = (F32)camera_offset.magVec();
- if(camera_distance > max_dist)
- {
- tethered = mAvatarPosition +
- (max_dist / camera_distance) * camera_offset;
- }
- }
-
- if(dist_vec(mCameraPosition, tethered) > 0.1)
- {
- mCameraPosition = tethered;
- mSpatialCoordsDirty = true;
- }
- }
- void LLVoiceClient::updatePosition(void)
- {
-
- if(gVoiceClient)
- {
- LLVOAvatar *agent = gAgent.getAvatarObject();
- LLViewerRegion *region = gAgent.getRegion();
- if(region && agent)
- {
- LLMatrix3 rot;
- LLVector3d pos;
- // TODO: If camera and avatar velocity are actually used by the voice system, we could compute them here...
- // They're currently always set to zero.
- // Send the current camera position to the voice code
- rot.setRows(LLViewerCamera::getInstance()->getAtAxis(), LLViewerCamera::getInstance()->getLeftAxis (), LLViewerCamera::getInstance()->getUpAxis());
- pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
-
- gVoiceClient->setCameraPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
-
- // Send the current avatar position to the voice code
- rot = agent->getRootJoint()->getWorldRotation().getMatrix3();
-
- pos = agent->getPositionGlobal();
- // TODO: Can we get the head offset from outside the LLVOAvatar?
- // pos += LLVector3d(mHeadOffset);
- pos += LLVector3d(0.f, 0.f, 1.f);
-
- gVoiceClient->setAvatarPosition(
- pos, // position
- LLVector3::zero, // velocity
- rot); // rotation matrix
- }
- }
- }
- void LLVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
- {
- mCameraRequestedPosition = position;
-
- if(mCameraVelocity != velocity)
- {
- mCameraVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mCameraRot != rot)
- {
- mCameraRot = rot;
- mSpatialCoordsDirty = true;
- }
- }
- void LLVoiceClient::setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLMatrix3 &rot)
- {
- if(dist_vec(mAvatarPosition, position) > 0.1)
- {
- mAvatarPosition = position;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarVelocity != velocity)
- {
- mAvatarVelocity = velocity;
- mSpatialCoordsDirty = true;
- }
-
- if(mAvatarRot != rot)
- {
- mAvatarRot = rot;
- mSpatialCoordsDirty = true;
- }
- }
- bool LLVoiceClient::channelFromRegion(LLViewerRegion *region, std::string &name)
- {
- bool result = false;
-
- if(region)
- {
- name = region->getName();
- }
-
- if(!name.empty())
- result = true;
-
- return result;
- }
- void LLVoiceClient::leaveChannel(void)
- {
- if(getState() == stateRunning)
- {
- LL_DEBUGS("Voice") << "leaving channel for teleport/logout" << LL_ENDL;
- mChannelName.clear();
- sessionTerminate();
- }
- }
- void LLVoiceClient::setMuteMic(bool muted)
- {
- mMuteMic = muted;
- }
- bool LLVoiceClient::getMuteMic() const
- {
- return mMuteMic;
- }
- void LLVoiceClient::setUserPTTState(bool ptt)
- {
- mUserPTTState = ptt;
- }
- bool LLVoiceClient::getUserPTTState()
- {
- return mUserPTTState;
- }
- void LLVoiceClient::toggleUserPTTState(void)
- {
- mUserPTTState = !mUserPTTState;
- }
- void LLVoiceClient::setVoiceEnabled(bool enabled)
- {
- if (enabled != mVoiceEnabled)
- {
- mVoiceEnabled = enabled;
- LLVoiceClientStatusObserver::EStatusType status;
- if (enabled)
- {
- LLVoiceChannel::getCurrentVoiceChannel()->activate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED;
- }
- else
- {
- // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it.
- LLVoiceChannel::getCurrentVoiceChannel()->deactivate();
- status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED;
- }
- notifyStatusObservers(status);
- }
- }
- bool LLVoiceClient::voiceEnabled()
- {
- return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
- }
- //AD *TODO: investigate possible merge of voiceWorking() and voiceEnabled() into one non-static method
- bool LLVoiceClient::voiceWorking()
- {
- //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758)
- return (stateLoggedIn <= mState) && (mState <= stateSessionTerminated);
- }
- void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
- {
- mLipSyncEnabled = enabled;
- }
- BOOL LLVoiceClient::lipSyncEnabled()
- {
-
- if ( mVoiceEnabled && stateDisabled != getState() )
- {
- return mLipSyncEnabled;
- }
- else
- {
- return FALSE;
- }
- }
- void LLVoiceClient::setUsePTT(bool usePTT)
- {
- if(usePTT && !mUsePTT)
- {
- // When the user turns on PTT, reset the current state.
- mUserPTTState = false;
- }
- mUsePTT = usePTT;
- }
- void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
- {
- if(!PTTIsToggle && mPTTIsToggle)
- {
- // When the user turns off toggle, reset the current state.
- mUserPTTState = false;
- }
-
- mPTTIsToggle = PTTIsToggle;
- }
- bool LLVoiceClient::getPTTIsToggle()
- {
- return mPTTIsToggle;
- }
- void LLVoiceClient::setPTTKey(std::string &key)
- {
- if(key == "MiddleMouse")
- {
- mPTTIsMiddleMouse = true;
- }
- else
- {
- mPTTIsMiddleMouse = false;
- if(!LLKeyboard::keyFromString(key, &mPTTKey))
- {
- // If the call failed, don't match any key.
- key = KEY_NONE;
- }
- }
- }
- void LLVoiceClient::setEarLocation(S32 loc)
- {
- if(mEarLocation != loc)
- {
- LL_DEBUGS("Voice") << "Setting mEarLocation to " << loc << LL_ENDL;
-
- mEarLocation = loc;
- mSpatialCoordsDirty = true;
- }
- }
- void LLVoiceClient::setVoiceVolume(F32 volume)
- {
- int scaled_volume = scale_speaker_volume(volume);
- if(scaled_volume != mSpeakerVolume)
- {
- int min_volume = scale_speaker_volume(0);
- if((scaled_volume == min_volume) || (mSpeakerVolume == min_volume))
- {
- mSpeakerMuteDirty = true;
- }
- mSpeakerVolume = scaled_volume;
- mSpeakerVolumeDirty = true;
- }
- }
- void LLVoiceClient::setMicGain(F32 volume)
- {
- int scaled_volume = scale_mic_volume(volume);
-
- if(scaled_volume != mMicVolume)
- {
- mMicVolume = scaled_volume;
- mMicVolumeDirty = true;
- }
- }
- void LLVoiceClient::keyDown(KEY key, MASK mask)
- {
- if (gKeyboard->getKeyRepeated(key))
- {
- // ignore auto-repeat keys
- return;
- }
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
- }
- void LLVoiceClient::keyUp(KEY key, MASK mask)
- {
- if(!mPTTIsMiddleMouse)
- {
- bool down = (mPTTKey != KEY_NONE)
- && gKeyboard->getKeyDown(mPTTKey);
- inputUserControlState(down);
- }
- }
- void LLVoiceClient::inputUserControlState(bool down)
- {
- if(mPTTIsToggle)
- {
- if(down) // toggle open-mic state on 'down'
- {
- toggleUserPTTState();
- }
- }
- else // set open-mic state as an absolute
- {
- setUserPTTState(down);
- }
- }
- void LLVoiceClient::middleMouseState(bool down)
- {
- if(mPTTIsMiddleMouse)
- {
- inputUserControlState(down);
- }
- }
- /////////////////////////////
- // Accessors for data related to nearby speakers
- BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id)
- {
- BOOL result = FALSE;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- // I'm not sure what the semantics of this should be.
- // For now, if we have any data about the user that came through the chat channel, assume they're voice-enabled.
- result = TRUE;
- }
-
- return result;
- }
- BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
- {
- BOOL result = FALSE;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- if (participant->mSpeakingTimeout.getElapsedTimeF32() > SPEAKING_TIMEOUT)
- {
- participant->mIsSpeaking = FALSE;
- }
- result = participant->mIsSpeaking;
- }
-
- return result;
- }
- BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
- {
- BOOL result = FALSE;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- result = participant->mIsModeratorMuted;
- }
-
- return result;
- }
- F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
- {
- F32 result = 0;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- result = participant->mPower;
- }
-
- return result;
- }
- std::string LLVoiceClient::getDisplayName(const LLUUID& id)
- {
- std::string result;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- result = participant->mDisplayName;
- }
-
- return result;
- }
- BOOL LLVoiceClient::getUsingPTT(const LLUUID& id)
- {
- BOOL result = FALSE;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- // I'm not sure what the semantics of this should be.
- // Does "using PTT" mean they're configured with a push-to-talk button?
- // For now, we know there's no PTT mechanism in place, so nobody is using it.
- }
-
- return result;
- }
- BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
- {
- BOOL result = FALSE;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- result = participant->mOnMuteList;
- }
- return result;
- }
- // External accessiors. Maps 0.0 to 1.0 to internal values 0-400 with .5 == 100
- // internal = 400 * external^2
- F32 LLVoiceClient::getUserVolume(const LLUUID& id)
- {
- F32 result = 0.0f;
-
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- S32 ires = 100; // nominal default volume
-
- if(participant->mIsSelf)
- {
- // Always make it look like the user's own volume is set at the default.
- }
- else if(participant->mUserVolume != -1)
- {
- // Use the internal volume
- ires = participant->mUserVolume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "mapping from mUserVolume " << ires << LL_ENDL;
- }
- else if(participant->mVolume != -1)
- {
- // Map backwards from vivox volume
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "mapping from mVolume " << participant->mVolume << LL_ENDL;
- if(participant->mVolume < 56)
- {
- ires = (participant->mVolume * 100) / 56;
- }
- else
- {
- ires = (((participant->mVolume - 56) * 300) / (100 - 56)) + 100;
- }
- }
- result = sqrtf(((F32)ires) / 400.f);
- }
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
- // LL_DEBUGS("Voice") << "returning " << result << LL_ENDL;
- return result;
- }
- void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
- {
- if(mAudioSession)
- {
- participantState *participant = findParticipantByID(id);
- if (participant)
- {
- // store this volume setting for future sessions
- LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
- // volume can amplify by as much as 4x!
- S32 ivol = (S32)(400.f * volume * volume);
- participant->mUserVolume = llclamp(ivol, 0, 400);
- participant->mVolumeDirty = TRUE;
- mAudioSession->mVolumeDirty = TRUE;
- }
- }
- }
- std::string LLVoiceClient::getGroupID(const LLUUID& id)
- {
- std::string result;
- participantState *participant = findParticipantByID(id);
- if(participant)
- {
- result = participant->mGroupID;
- }
-
- return result;
- }
- BOOL LLVoiceClient::getAreaVoiceDisabled()
- {
- return mAreaVoiceDisabled;
- }
- void LLVoiceClient::recordingLoopStart(int seconds, int deltaFramesPerControlFrame)
- {
- // LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Start)" << LL_ENDL;
-
- if(!mMainSessionGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="SessionGroup.ControlRecording.1">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<DeltaFramesPerControlFrame>" << deltaFramesPerControlFrame << "</DeltaFramesPerControlFrame>"
- << "<Filename>" << "" << "</Filename>"
- << "<EnableAudioRecordingEvents>false</EnableAudioRecordingEvents>"
- << "<LoopModeDurationSeconds>" << seconds << "</LoopModeDurationSeconds>"
- << "</Request>nnn";
- writeString(stream.str());
- }
- }
- void LLVoiceClient::recordingLoopSave(const std::string& filename)
- {
- // LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Flush)" << LL_ENDL;
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="SessionGroup.ControlRecording.1">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Flush</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>nnn";
- writeString(stream.str());
- }
- }
- void LLVoiceClient::recordingStop()
- {
- // LL_DEBUGS("Voice") << "sending SessionGroup.ControlRecording (Stop)" << LL_ENDL;
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="SessionGroup.ControlRecording.1">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>nnn";
- writeString(stream.str());
- }
- }
- void LLVoiceClient::filePlaybackStart(const std::string& filename)
- {
- // LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Start)" << LL_ENDL;
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="SessionGroup.ControlPlayback.1">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Start</RecordingControlType>"
- << "<Filename>" << filename << "</Filename>"
- << "</Request>nnn";
- writeString(stream.str());
- }
- }
- void LLVoiceClient::filePlaybackStop()
- {
- // LL_DEBUGS("Voice") << "sending SessionGroup.ControlPlayback (Stop)" << LL_ENDL;
- if(mAudioSession != NULL && !mAudioSession->mGroupHandle.empty())
- {
- std::ostringstream stream;
- stream
- << "<Request requestId="" << mCommandCookie++ << "" action="SessionGroup.ControlPlayback.1">"
- << "<SessionGroupHandle>" << mMainSessionGroupHandle << "</SessionGroupHandle>"
- << "<RecordingControlType>Stop</RecordingControlType>"
- << "</Request>nnn";
- writeString(stream.str());
- }
- }
- void LLVoiceClient::filePlaybackSetPaused(bool paused)
- {
- // TODO: Implement once Vivox gives me a sample
- }
- void LLVoiceClient::filePlaybackSetMode(bool vox, float speed)
- {
- // TODO: Implement once Vivox gives me a sample
- }
- LLVoiceClient::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),
- mParticipantsChanged(false)
- {
- }
- LLVoiceClient::sessionState::~sessionState()
- {
- removeAllParticipants();
- }
- bool LLVoiceClient::sessionState::isCallBackPossible()
- {
- // This may change to be explicitly specified by vivox in the future...
- // Currently, only PSTN P2P calls cannot be returned.
- // Conveniently, this is also the only case where we synthesize a caller UUID.
- return !mSynthesizedCallerID;
- }
- bool LLVoiceClient::sessionState::isTextIMPossible()
- {
- // This may change to be explicitly specified by vivox in the future...
- return !mSynthesizedCallerID;
- }
- LLVoiceClient::sessionIterator LLVoiceClient::sessionsBegin(void)
- {
- return mSessions.begin();
- }
- LLVoiceClient::sessionIterator LLVoiceClient::sessionsEnd(void)
- {
- return mSessions.end();
- }
- LLVoiceClient::sessionState *LLVoiceClient::findSession(const std::string &handle)
- {
- sessionState *result = NULL;
- sessionMap::iterator iter = mSessionsByHandle.find(&handle);
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
-
- return result;
- }
- LLVoiceClient::sessionState *LLVoiceClient::findSessionBeingCreatedByURI(const std::string &uri)
- {
- sessionState *result = NULL;
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- if(session->mCreateInProgress && (session->mSIPURI == uri))
- {
- result = session;
- break;
- }
- }
-
- return result;
- }
- LLVoiceClient::sessionState *LLVoiceClient::findSession(const LLUUID &participant_id)
- {
- sessionState *result = NULL;
-
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id))
- {
- result = session;
- break;
- }
- }
-
- return result;
- }
- LLVoiceClient::sessionState *LLVoiceClient::addSession(const std::string &uri, const std::string &handle)
- {
- sessionState *result = NULL;
-
- if(handle.empty())
- {
- // No handle supplied.
- // Check whether there's already a session with this URI
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *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;
- }
- }
- }
- else // (!handle.empty())
- {
- // Check for an existing session with this handle
- sessionMap::iterator iter = mSessionsByHandle.find(&handle);
-
- if(iter != mSessionsByHandle.end())
- {
- result = iter->second;
- }
- }
- if(!result)
- {
- // No existing session found.
-
- LL_DEBUGS("Voice") << "adding new session: handle " << handle << " URI " << uri << LL_ENDL;
- result = new sessionState();
- result->mSIPURI = uri;
- result->mHandle = handle;
-
- mSessions.insert(result);
- if(!result->mHandle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(&(result->mHandle), result));
- }
- }
- else
- {
- // Found an existing session
-
- if(uri != result->mSIPURI)
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing uri from " << result->mSIPURI << " to " << uri << LL_ENDL;
- setSessionURI(result, uri);
- }
- if(handle != result->mHandle)
- {
- if(handle.empty())
- {
- // There's at least one race condition where where addSession was clearing an existing session handle, which caused things to break.
- LL_DEBUGS("Voice") << "NOT clearing handle " << result->mHandle << LL_ENDL;
- }
- else
- {
- // TODO: Should this be an internal error?
- LL_DEBUGS("Voice") << "changing handle from " << result->mHandle << " to " << handle << LL_ENDL;
- setSessionHandle(result, handle);
- }
- }
-
- LL_DEBUGS("Voice") << "returning existing session: handle " << handle << " URI " << uri << LL_ENDL;
- }
- verifySessionState();
-
- return result;
- }
- void LLVoiceClient::setSessionHandle(sessionState *session, const std::string &handle)
- {
- // Have to remove the session from the handle-indexed map before changing the handle, or things will break badly.
-
- if(!session->mHandle.empty())
- {
- // Remove session from the map if it should have been there.
- sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle));
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_ERRS("Voice") << "Internal error: session mismatch!" << LL_ENDL;
- }
- mSessionsByHandle.erase(iter);
- }
- else
- {
- LL_ERRS("Voice") << "Internal error: session handle not found in map!" << LL_ENDL;
- }
- }
-
- session->mHandle = handle;
- if(!handle.empty())
- {
- mSessionsByHandle.insert(sessionMap::value_type(&(session->mHandle), session));
- }
- verifySessionState();
- }
- void LLVoiceClient::setSessionURI(sessionState *session, const std::string &uri)
- {
- // There used to be a map of session URIs to sessions, which made this complex....
- session->mSIPURI = uri;
- verifySessionState();
- }
- void LLVoiceClient::deleteSession(sessionState *session)
- {
- // Remove the session from the handle map
- if(!session->mHandle.empty())
- {
- sessionMap::iterator iter = mSessionsByHandle.find(&(session->mHandle));
- if(iter != mSessionsByHandle.end())
- {
- if(iter->second != session)
- {
- LL_ERRS("Voice") << "Internal error: session mismatch" << LL_ENDL;
- }
- mSessionsByHandle.erase(iter);
- }
- }
- // 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();
- // If this is the current audio session, clean up the pointer which will soon be dangling.
- if(mAudioSession == session)
- {
- mAudioSession = NULL;
- mAudioSessionChanged = true;
- }
- // ditto for the next audio session
- if(mNextAudioSession == session)
- {
- mNextAudioSession = NULL;
- }
- // delete the session
- delete session;
- }
- void LLVoiceClient::deleteAllSessions()
- {
- LL_DEBUGS("Voice") << "called" << LL_ENDL;
- while(!mSessions.empty())
- {
- deleteSession(*(sessionsBegin()));
- }
-
- if(!mSessionsByHandle.empty())
- {
- LL_ERRS("Voice") << "Internal error: empty session map, non-empty handle map" << LL_ENDL;
- }
- }
- void LLVoiceClient::verifySessionState(void)
- {
- // 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;
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- LL_DEBUGS("Voice") << "session " << session << ": handle " << session->mHandle << ", URI " << session->mSIPURI << LL_ENDL;
-
- if(!session->mHandle.empty())
- {
- // every session with a non-empty handle needs to be in the handle map
- sessionMap::iterator i2 = mSessionsByHandle.find(&(session->mHandle));
- if(i2 == mSessionsByHandle.end())
- {
- LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " not found in session map)" << LL_ENDL;
- }
- else
- {
- if(i2->second != session)
- {
- LL_ERRS("Voice") << "internal error (handle " << session->mHandle << " in session map points to another session)" << LL_ENDL;
- }
- }
- }
- }
-
- // 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++)
- {
- sessionState *session = iter->second;
- sessionIterator i2 = mSessions.find(session);
- if(i2 == mSessions.end())
- {
- LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " not found in session map)" << LL_ENDL;
- }
- else
- {
- if(session->mHandle != (*i2)->mHandle)
- {
- LL_ERRS("Voice") << "internal error (session for handle " << session->mHandle << " points to session with different handle " << (*i2)->mHandle << ")" << LL_ENDL;
- }
- }
- }
- }
- LLVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) :
- mURI(uri)
- {
- mOnlineSL = false;
- mOnlineSLim = false;
- mCanSeeMeOnline = true;
- mHasBlockListEntry = false;
- mHasAutoAcceptListEntry = false;
- mNameResolved = false;
- mInVivoxBuddies = false;
- mInSLFriends = false;
- mNeedsNameUpdate = false;
- }
- void LLVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName)
- {
- buddyListEntry *buddy = addBuddy(uri, displayName);
- buddy->mInVivoxBuddies = true;
- }
- LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri)
- {
- std::string empty;
- buddyListEntry *buddy = addBuddy(uri, empty);
- if(buddy->mDisplayName.empty())
- {
- buddy->mNameResolved = false;
- }
- return buddy;
- }
- LLVoiceClient::buddyListEntry *LLVoiceClient::addBuddy(const std::string &uri, const std::string &displayName)
- {
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
-
- if(iter != mBuddyListMap.end())
- {
- // Found a matching buddy already in the map.
- LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL;
- result = iter->second;
- }
- if(!result)
- {
- // participant isn't already in one list or the other.
- LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL;
- result = new buddyListEntry(uri);
- result->mDisplayName = displayName;
- if(IDFromName(uri, result->mUUID))
- {
- // Extracted UUID from name successfully.
- }
- else
- {
- LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " ("" << displayName << "")" << LL_ENDL;
- }
- mBuddyListMap.insert(buddyListMap::value_type(&(result->mURI), result));
- }
-
- return result;
- }
- LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const std::string &uri)
- {
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
- if(iter != mBuddyListMap.end())
- {
- result = iter->second;
- }
-
- return result;
- }
- LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddy(const LLUUID &id)
- {
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter;
- for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
- {
- if(iter->second->mUUID == id)
- {
- result = iter->second;
- break;
- }
- }
-
- return result;
- }
- LLVoiceClient::buddyListEntry *LLVoiceClient::findBuddyByDisplayName(const std::string &name)
- {
- buddyListEntry *result = NULL;
- buddyListMap::iterator iter;
- for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++)
- {
- if(iter->second->mDisplayName == name)
- {
- result = iter->second;
- break;
- }
- }
-
- return result;
- }
- void LLVoiceClient::deleteBuddy(const std::string &uri)
- {
- buddyListMap::iterator iter = mBuddyListMap.find(&uri);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL;
- buddyListEntry *buddy = iter->second;
- mBuddyListMap.erase(iter);
- delete buddy;
- }
- else
- {
- LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL;
- }
-
- }
- void LLVoiceClient::deleteAllBuddies(void)
- {
- while(!mBuddyListMap.empty())
- {
- deleteBuddy(*(mBuddyListMap.begin()->first));
- }
-
- // Don't want to correlate with friends list when we've emptied the buddy list.
- mBuddyListMapPopulated = false;
-
- // Don't want to correlate with friends list when we've reset the block rules.
- mBlockRulesListReceived = false;
- mAutoAcceptRulesListReceived = false;
- }
- void LLVoiceClient::deleteAllBlockRules(void)
- {
- // Clear the block list entry flags from all local buddy list entries
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- buddy_it->second->mHasBlockListEntry = false;
- }
- }
- void LLVoiceClient::deleteAllAutoAcceptRules(void)
- {
- // Clear the auto-accept list entry flags from all local buddy list entries
- buddyListMap::iterator buddy_it;
- for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++)
- {
- buddy_it->second->mHasAutoAcceptListEntry = false;
- }
- }
- void LLVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly)
- {
- buddyListEntry *buddy = NULL;
- // blockMask is the SIP URI of a friends list entry
- buddyListMap::iterator iter = mBuddyListMap.find(&blockMask);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL;
- buddy = iter->second;
- }
- if(buddy == NULL)
- {
- LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL;
- buddy = addBuddy(blockMask);
- }
-
- if(buddy != NULL)
- {
- buddy->mHasBlockListEntry = true;
- }
- }
- void LLVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy)
- {
- buddyListEntry *buddy = NULL;
- // blockMask is the SIP URI of a friends list entry
- buddyListMap::iterator iter = mBuddyListMap.find(&autoAcceptMask);
- if(iter != mBuddyListMap.end())
- {
- LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL;
- buddy = iter->second;
- }
- if(buddy == NULL)
- {
- LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL;
- buddy = addBuddy(autoAcceptMask);
- }
- if(buddy != NULL)
- {
- buddy->mHasAutoAcceptListEntry = true;
- }
- }
- void LLVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString)
- {
- // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
- mBlockRulesListReceived = true;
- }
- void LLVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString)
- {
- // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done.
- mAutoAcceptRulesListReceived = true;
- }
- void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
- {
- mParticipantObservers.insert(observer);
- }
- void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
- {
- mParticipantObservers.erase(observer);
- }
- void LLVoiceClient::notifyParticipantObservers()
- {
- for (observer_set_t::iterator it = mParticipantObservers.begin();
- it != mParticipantObservers.end();
- )
- {
- LLVoiceClientParticipantObserver* observer = *it;
- observer->onChange();
- // In case onChange() deleted an entry.
- it = mParticipantObservers.upper_bound(observer);
- }
- }
- void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
- {
- mStatusObservers.insert(observer);
- }
- void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
- {
- mStatusObservers.erase(observer);
- }
- void LLVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::EStatusType status)
- {
- if(mAudioSession)
- {
- if(status == LLVoiceClientStatusObserver::ERROR_UNKNOWN)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 20713: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_FULL; break;
- case 20714: status = LLVoiceClientStatusObserver::ERROR_CHANNEL_LOCKED; break;
- case 20715:
- //invalid channel, we may be using a set of poorly cached
- //info
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- case 1009:
- //invalid username and password
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- break;
- }
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- }
- else if(status == LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL)
- {
- switch(mAudioSession->mErrorStatusCode)
- {
- case 404: // NOT_FOUND
- case 480: // TEMPORARILY_UNAVAILABLE
- case 408: // REQUEST_TIMEOUT
- // call failed because other user was not available
- // treat this as an error case
- status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
- // Reset the error code to make sure it won't be reused later by accident.
- mAudioSession->mErrorStatusCode = 0;
- break;
- }
- }
- }
-
- LL_DEBUGS("Voice")
- << " " << LLVoiceClientStatusObserver::status2string(status)
- << ", session URI " << getAudioSessionURI()
- << (inSpatialChannel()?", proximal is true":", proximal is false")
- << LL_ENDL;
- for (status_observer_set_t::iterator it = mStatusObservers.begin();
- it != mStatusObservers.end();
- )
- {
- LLVoiceClientStatusObserver* observer = *it;
- observer->onChange(status, getAudioSessionURI(), inSpatialChannel());
- // In case onError() deleted an entry.
- it = mStatusObservers.upper_bound(observer);
- }
- }
- void LLVoiceClient::addObserver(LLFriendObserver* observer)
- {
- mFriendObservers.insert(observer);
- }
- void LLVoiceClient::removeObserver(LLFriendObserver* observer)
- {
- mFriendObservers.erase(observer);
- }
- void LLVoiceClient::notifyFriendObservers()
- {
- for (friend_observer_set_t::iterator it = mFriendObservers.begin();
- it != mFriendObservers.end();
- )
- {
- LLFriendObserver* observer = *it;
- it++;
- // The only friend-related thing we notify on is online/offline transitions.
- observer->changed(LLFriendObserver::ONLINE);
- }
- }
- void LLVoiceClient::lookupName(const LLUUID &id)
- {
- BOOL is_group = FALSE;
- gCacheName->get(id, is_group, &LLVoiceClient::onAvatarNameLookup);
- }
- //static
- void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
- {
- if(gVoiceClient)
- {
- std::string name = llformat("%s %s", first.c_str(), last.c_str());
- gVoiceClient->avatarNameResolved(id, name);
- }
- }
- void LLVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name)
- {
- // If the avatar whose name just resolved is on our friends list, resync the friends list.
- if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL)
- {
- mFriendsListDirty = true;
- }
-
- // Iterate over all sessions.
- for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
- {
- sessionState *session = *iter;
- // Check for this user as a participant in this session
- participantState *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 gIMMgr->addP2PSession() here. The first incoming message will create the panel.
- }
- if(session->mVoiceInvitePending)
- {
- session->mVoiceInvitePending = false;
- gIMMgr->inviteToSession(
- session->mIMSessionID,
- session->mName,
- session->mCallerID,
- session->mName,
- IM_SESSION_P2P_INVITE,
- LLIMMgr::INVITATION_TYPE_VOICE,
- session->mHandle,
- session->mSIPURI);
- }
-
- }
- }
- }
- class LLViewerParcelVoiceInfo : public LLHTTPNode
- {
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- //the parcel you are in has changed something about its
- //voice information
- //this is a misnomer, as it can also be when you are not in
- //a parcel at all. Should really be something like
- //LLViewerVoiceInfoChanged.....
- if ( input.has("body") )
- {
- LLSD body = input["body"];
- //body has "region_name" (str), "parcel_local_id"(int),
- //"voice_credentials" (map).
- //body["voice_credentials"] has "channel_uri" (str),
- //body["voice_credentials"] has "channel_credentials" (str)
- //if we really wanted to be extra careful,
- //we'd check the supplied
- //local parcel id to make sure it's for the same parcel
- //we believe we're in
- if ( body.has("voice_credentials") )
- {
- LLSD voice_credentials = body["voice_credentials"];
- std::string uri;
- std::string credentials;
- if ( voice_credentials.has("channel_uri") )
- {
- uri = voice_credentials["channel_uri"].asString();
- }
- if ( voice_credentials.has("channel_credentials") )
- {
- credentials =
- voice_credentials["channel_credentials"].asString();
- }
- gVoiceClient->setSpatialChannel(uri, credentials);
- }
- }
- }
- };
- class LLViewerRequiredVoiceVersion : public LLHTTPNode
- {
- static BOOL sAlertedUser;
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- //You received this messsage (most likely on region cross or
- //teleport)
- if ( input.has("body") && input["body"].has("major_version") )
- {
- int major_voice_version =
- input["body"]["major_version"].asInteger();
- // int minor_voice_version =
- // input["body"]["minor_version"].asInteger();
- if (gVoiceClient &&
- (major_voice_version > VOICE_MAJOR_VERSION) )
- {
- if (!sAlertedUser)
- {
- //sAlertedUser = TRUE;
- LLNotificationsUtil::add("VoiceVersionMismatch");
- gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener
- }
- }
- }
- }
- };
- BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;
- LLHTTPRegistration<LLViewerParcelVoiceInfo>
- gHTTPRegistrationMessageParcelVoiceInfo(
- "/message/ParcelVoiceInfo");
- LLHTTPRegistration<LLViewerRequiredVoiceVersion>
- gHTTPRegistrationMessageRequiredVoiceVersion(
- "/message/RequiredVoiceVersion");