From 5dfd435872e36445dcc82f99443dfc5a7ee0805a Mon Sep 17 00:00:00 2001
From: Monroe Williams <monroe@lindenlab.com>
Date: Thu, 19 Mar 2009 19:18:07 +0000
Subject: [PATCH] svn merge -r 114639:114640
 svn+ssh://svn.lindenlab.com/svn/linden/branches/qar-1361

Merging in QAR-1361.
---
 indra/newview/llimpanel.cpp     |  24 +++-
 indra/newview/llimpanel.h       |   4 +
 indra/newview/llvoiceclient.cpp | 240 ++++++++++++++++++++++++++++----
 indra/newview/llvoiceclient.h   |  20 +++
 install.xml                     |  12 +-
 5 files changed, 265 insertions(+), 35 deletions(-)

diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index f3943345c7b..fcebfa70533 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -1120,6 +1120,9 @@ LLFloaterIMPanel::LLFloaterIMPanel(
 	mSentTypingState(TRUE),
 	mShowSpeakersOnConnect(TRUE),
 	mAutoConnect(FALSE),
+	mTextIMPossible(TRUE),
+	mProfileButtonEnabled(TRUE),
+	mCallBackEnabled(TRUE),
 	mSpeakers(NULL),
 	mSpeakerPanel(NULL),
 	mFirstKeystrokeTimer(),
@@ -1165,7 +1168,13 @@ void LLFloaterIMPanel::init(const std::string& session_label)
 		break;
 	// just received text from another user
 	case IM_NOTHING_SPECIAL:
+
 		xml_filename = "floater_instant_message.xml";
+		
+		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID);
+		mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID);
+		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID);
+		
 		mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID);
 		break;
 	default:
@@ -1297,6 +1306,11 @@ BOOL LLFloaterIMPanel::postBuild()
 		{
 			childSetEnabled("profile_btn", FALSE);
 		}
+		
+		if(!mProfileButtonEnabled)
+		{
+			childSetEnabled("profile_callee_btn", FALSE);
+		}
 
 		sTitleString = getString("title_string");
 		sTypingStartString = getString("typing_start_string");
@@ -1365,7 +1379,8 @@ void LLFloaterIMPanel::draw()
 	
 	BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "")
 					  && mSessionInitialized
-					  && LLVoiceClient::voiceEnabled();
+					  && LLVoiceClient::voiceEnabled()
+					  && mCallBackEnabled;
 
 	// hide/show start call and end call buttons
 	childSetVisible("end_call_btn", LLVoiceClient::voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED);
@@ -1374,7 +1389,12 @@ void LLFloaterIMPanel::draw()
 	childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty());
 	
 	LLPointer<LLSpeaker> self_speaker = mSpeakers->findSpeaker(gAgent.getID());
-	if (self_speaker.notNull() && self_speaker->mModeratorMutedText)
+	if(!mTextIMPossible)
+	{
+		mInputEditor->setEnabled(FALSE);
+		mInputEditor->setLabel(getString("unavailable_text_label"));
+	}
+	else if (self_speaker.notNull() && self_speaker->mModeratorMutedText)
 	{
 		mInputEditor->setEnabled(FALSE);
 		mInputEditor->setLabel(getString("muted_text_label"));
diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h
index e54cec56c7f..8b3ca202c7d 100644
--- a/indra/newview/llimpanel.h
+++ b/indra/newview/llimpanel.h
@@ -343,6 +343,10 @@ class LLFloaterIMPanel : public LLFloater
 	BOOL mShowSpeakersOnConnect;
 
 	BOOL mAutoConnect;
+	
+	BOOL mTextIMPossible;
+	BOOL mProfileButtonEnabled;
+	BOOL mCallBackEnabled;
 
 	LLIMSpeakerMgr* mSpeakers;
 	LLPanelActiveSpeakers* mSpeakerPanel;
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 3bcc0af7d5f..94407ed08ce 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -844,6 +844,16 @@ void LLVivoxProtocolParser::processResponse(std::string tag)
 			*/
 			// We don't need to process this, but we also shouldn't warn on it, since that confuses people.
 		}
+		
+		else if (!stricmp(eventTypeCstr, "SessionGroupRemovedEvent"))  
+		{
+			/*
+			<Event type="SessionGroupRemovedEvent">
+				<SessionGroupHandle>c1_m1000xFnPP04IpREWNkuw1cOXlhw==_sg0</SessionGroupHandle>
+			</Event>
+			*/
+			// We don't need to process this, but we also shouldn't warn on it, since that confuses people.
+		}
 		else
 		{
 			LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL;
@@ -1560,20 +1570,27 @@ void LLVoiceClient::stateMachine()
 			std::string regionName = region->getName();
 			std::string capURI = region->getCapability("ParcelVoiceInfoRequest");
 		
-//			LL_DEBUGS("Voice") << "Region name = \"" << regionName <<"\", " << "parcel local ID = " << parcelLocalID << LL_ENDL;
+//			LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
 
 			// The region name starts out empty and gets filled in later.  
 			// Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
 			// If either is empty, wait for the next time around.
-			if(!regionName.empty() && !capURI.empty())
+			if(!regionName.empty())
 			{
-				if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
+				if(!capURI.empty())
 				{
-					// We have changed parcels.  Initiate a parcel channel lookup.
-					mCurrentParcelLocalID = parcelLocalID;
-					mCurrentRegionName = regionName;
-					
-					parcelChanged();
+					if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
+					{
+						// We have changed parcels.  Initiate a parcel channel lookup.
+						mCurrentParcelLocalID = parcelLocalID;
+						mCurrentRegionName = regionName;
+						
+						parcelChanged();
+					}
+				}
+				else
+				{
+					LL_WARNS("Voice") << "region doesn't have ParcelVoiceInfoRequest capability.  This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL;
 				}
 			}
 		}
@@ -1840,6 +1857,10 @@ void LLVoiceClient::stateMachine()
 						}
 						setState(stateConnectorStart);
 					}
+					else
+					{
+						LL_WARNS("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL;
+					}
 				}
 			}
 		break;
@@ -2308,12 +2329,27 @@ void LLVoiceClient::stateMachine()
 		
 		//MARK: stateLoggingOut
 		case stateLoggingOut:			// waiting for logout response
-			// The handler for the Account.Logout response will transition from here to stateLoggedOut.
+			// The handler for the AccountLoginStateChangeEvent will transition from here to stateLoggedOut.
 		break;
+		
 		//MARK: stateLoggedOut
 		case stateLoggedOut:			// logout response received
-			// shut down the connector
-			connectorShutdown();
+			
+			// Once we're logged out, all these things are invalid.
+			mAccountHandle.clear();
+			deleteAllSessions();
+			deleteAllBuddies();
+
+			if(mVoiceEnabled && !mRelogRequested)
+			{
+				// User was logged out, but wants to be logged in.  Send a new login request.
+				setState(stateNeedsLogin);
+			}
+			else
+			{
+				// shut down the connector
+				connectorShutdown();
+			}
 		break;
 		
 		//MARK: stateConnectorStopping
@@ -2332,6 +2368,10 @@ void LLVoiceClient::stateMachine()
 		break;
 		//MARK: stateConnectorFailedWaiting
 		case stateConnectorFailedWaiting:
+			if(!mVoiceEnabled)
+			{
+				setState(stateDisableCleanup);
+			}
 		break;
 
 		//MARK: stateLoginFailed
@@ -2340,7 +2380,10 @@ void LLVoiceClient::stateMachine()
 		break;
 		//MARK: stateLoginFailedWaiting
 		case stateLoginFailedWaiting:
-			// No way to recover from these.  Yet.
+			if(!mVoiceEnabled)
+			{
+				setState(stateDisableCleanup);
+			}
 		break;
 
 		//MARK: stateJoinSessionFailed
@@ -2689,6 +2732,19 @@ void LLVoiceClient::sessionTerminateSendMessage(sessionState *session)
 	writeString(stream.str());
 }
 
+void LLVoiceClient::sessionGroupTerminateSendMessage(sessionState *session)
+{
+	std::ostringstream stream;
+	
+	LL_DEBUGS("Voice") << "Sending SessionGroup.Terminate with handle " << session->mGroupHandle << LL_ENDL;	
+	stream
+	<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"SessionGroup.Terminate.1\">"
+		<< "<SessionGroupHandle>" << session->mGroupHandle << "</SessionGroupHandle>"
+	<< "</Request>\n\n\n";
+	
+	writeString(stream.str());
+}
+
 void LLVoiceClient::sessionMediaDisconnectSendMessage(sessionState *session)
 {
 	std::ostringstream stream;
@@ -3227,14 +3283,23 @@ void LLVoiceClient::sendPositionalUpdate(void)
 				// Can't set volume/mute for yourself
 				if(!p->mIsSelf)
 				{
-					int volume = p->mUserVolume;
+					int volume = 56; // nominal default value
 					bool mute = p->mOnMuteList;
+					
+					if(p->mUserVolume != -1)
+					{
+						// scale from user volume in the range 0-400 (with 100 as "normal") to vivox volume in the range 0-100 (with 56 as "normal")
+						if(p->mUserVolume < 100)
+							volume = (p->mUserVolume * 56) / 100;
+						else
+							volume = (((p->mUserVolume - 100) * (100 - 56)) / 300) + 56;
+					}
+					else if(p->mVolume != -1)
+					{
+						// Use the previously reported internal volume (comes in with a ParticipantUpdatedEvent)
+						volume = p->mVolume;
+					}
 										
-					// SLIM SDK: scale volume from 0-400 (with 100 as "normal") to 0-100 (with 56 as "normal")
-					if(volume < 100)
-						volume = (volume * 56) / 100;
-					else
-						volume = (((volume - 100) * (100 - 56)) / 300) + 56;
 
 					if(mute)
 					{
@@ -3813,11 +3878,6 @@ void LLVoiceClient::logoutResponse(int statusCode, std::string &statusString)
 		LL_WARNS("Voice") << "Account.Logout response failure: " << statusString << LL_ENDL;
 		// Should this ever fail?  do we care if it does?
 	}
-	
-	if(getState() == stateLoggingOut)
-	{
-		setState(stateLoggedOut);
-	}
 }
 
 void LLVoiceClient::connectorShutdownResponse(int statusCode, std::string &statusString)
@@ -3990,6 +4050,10 @@ void LLVoiceClient::sessionRemovedEvent(
 		// 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;
@@ -4131,6 +4195,16 @@ void LLVoiceClient::accountLoginStateChangeEvent(
 			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
@@ -4756,9 +4830,9 @@ LLVoiceClient::participantState::participantState(const std::string &uri) :
 	 mIsModeratorMuted(false), 
 	 mLastSpokeTimestamp(0.f), 
 	 mPower(0.f), 
-	 mVolume(0), 
+	 mVolume(-1), 
 	 mOnMuteList(false), 
-	 mUserVolume(100), 
+	 mUserVolume(-1), 
 	 mVolumeDirty(false), 
 	 mAvatarIDValid(false),
 	 mIsSelf(false)
@@ -4843,6 +4917,11 @@ bool LLVoiceClient::participantState::updateMuteState()
 	return result;
 }
 
+bool LLVoiceClient::participantState::isAvatar()
+{
+	return mAvatarIDValid;
+}
+
 void LLVoiceClient::sessionState::removeParticipant(LLVoiceClient::participantState *participant)
 {
 	if(participant)
@@ -5276,6 +5355,66 @@ bool LLVoiceClient::isOnlineSIP(const LLUUID &id)
 	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);
@@ -5928,10 +6067,42 @@ F32 LLVoiceClient::getUserVolume(const LLUUID& id)
 	participantState *participant = findParticipantByID(id);
 	if(participant)
 	{
-		S32 ires = participant->mUserVolume; // 0-400
+		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;
 }
 
@@ -6095,6 +6266,21 @@ 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();
@@ -6141,7 +6327,7 @@ LLVoiceClient::sessionState *LLVoiceClient::findSession(const LLUUID &participan
 	for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++)
 	{
 		sessionState *session = *iter;
-		if(session->mCallerID == participant_id)
+		if((session->mCallerID == participant_id) || (session->mIMSessionID == participant_id))
 		{
 			result = session;
 			break;
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 43bbc8e29c1..cfc336b27db 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -255,6 +255,7 @@ static	void updatePosition(void);
 			participantState(const std::string &uri);
 
 			bool updateMuteState();
+			bool isAvatar();
 
 			std::string mURI;
 			LLUUID mAvatarID;
@@ -301,6 +302,9 @@ static	void updatePosition(void);
 			participantState *findParticipant(const std::string &uri);
 			participantState *findParticipantByID(const LLUUID& id);
 
+			bool isCallBackPossible();
+			bool isTextIMPossible();
+
 			std::string mHandle;
 			std::string mGroupHandle;
 			std::string mSIPURI;
@@ -434,6 +438,7 @@ static	void updatePosition(void);
 		void sessionMediaConnectSendMessage(sessionState *session);		// just joins the audio session
 		void sessionTextConnectSendMessage(sessionState *session);		// just joins the text session
 		void sessionTerminateSendMessage(sessionState *session);
+		void sessionGroupTerminateSendMessage(sessionState *session);
 		void sessionMediaDisconnectSendMessage(sessionState *session);
 		void sessionTextDisconnectSendMessage(sessionState *session);
 
@@ -496,6 +501,21 @@ static	void updatePosition(void);
 		// Returns true if the indicated user is online via SIP presence according to SLVoice.
 		// Note that we only get SIP presence data for other users that are in our vivox buddy list.
 		bool isOnlineSIP(const LLUUID &id);
+
+		// Returns true if the indicated participant is really an SL avatar.
+		// This should be used to control the state of the "profile" button.
+		// Currently this will be false only for PSTN callers into group chats, and PSTN p2p calls.
+		bool isParticipantAvatar(const LLUUID &id);
+		
+		// Returns true if calling back the session URI after the session has closed is possible.
+		// Currently this will be false only for PSTN P2P calls.		
+		// NOTE: this will return true if the session can't be found. 
+		bool isSessionCallBackPossible(const LLUUID &session_id);
+		
+		// Returns true if the session can accepte text IM's.
+		// Currently this will be false only for PSTN P2P calls.
+		// NOTE: this will return true if the session can't be found. 
+		bool isSessionTextIMPossible(const LLUUID &session_id);
 		
 	private:
 
diff --git a/install.xml b/install.xml
index b60fc7494b7..b4941bd3e24 100644
--- a/install.xml
+++ b/install.xml
@@ -1193,23 +1193,23 @@ anguage Infrstructure (CLI) international standard</string>
           <key>darwin</key>
           <map>
             <key>md5sum</key>
-            <string>352eae0cd76bb561da7b4183fc5a2857</string>
+            <string>8675b5eedef038b514338b17f0e55961</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6151-darwin-20090218.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-darwin-20090309.tar.bz2</uri>
           </map>
           <key>linux</key>
           <map>
             <key>md5sum</key>
-            <string>2279e1637568a837d9a4971cd27ed5f7</string>
+            <string>01573510dce7f380f44e561ef2f3dd9f</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6151-linux-20090218.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-linux-20090309.tar.bz2</uri>
           </map>
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>311bedab0abbd3a0ddf07216711af0ea</string>
+            <string>752daa90e07c05202d1f76980cb955eb</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6151-windows-20090218.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/vivox-2.1.3010.6270-windows-20090309.tar.bz2</uri>
           </map>
         </map>
       </map>
-- 
GitLab