From ed3a1c57733b65c1738d7235f8696957a8eee36a Mon Sep 17 00:00:00 2001
From: Roxie Linden <roxie@lindenlab.com>
Date: Tue, 19 Dec 2023 12:26:05 -0800
Subject: Connect to close neighboring regions and mute outgoing to them

---
 indra/newview/llvoicewebrtc.cpp | 300 +++++++++++++++++++++++-----------------
 indra/newview/llvoicewebrtc.h   |  47 ++++---
 2 files changed, 199 insertions(+), 148 deletions(-)

diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index 9a1b3525d7..0ff8a09de8 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -85,6 +85,8 @@ extern LLMenuBarGL* gMenuBarView;
 extern void handle_voice_morphing_subscribe();
 
 namespace {
+
+    const F32 MAX_AUDIO_DIST      = 50.0f;
     const F32 VOLUME_SCALE_WEBRTC = 0.01f;
     const F32 LEVEL_SCALE_WEBRTC  = 0.008f;
 
@@ -391,56 +393,35 @@ void LLWebRTCVoiceClient::updateSettings()
 /////////////////////////////
 // session control messages
 
-void LLWebRTCVoiceClient::predOnConnectionEstablished(const LLWebRTCVoiceClient::sessionStatePtr_t& session, std::string channelID)
-{
-    session->OnConnectionEstablished(channelID);
-}
-
-void LLWebRTCVoiceClient::predOnConnectionFailure(const LLWebRTCVoiceClient::sessionStatePtr_t& session, std::string channelID)
-{
-    session->OnConnectionFailure(channelID);
-}
-
-void LLWebRTCVoiceClient::OnConnectionFailure(const std::string& channelID)
-{
-    if (mNextAudioSession && mNextAudioSession->mChannelID == channelID)
-    {
-        LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
-    }
-    else if (mAudioSession && mAudioSession->mChannelID == channelID)
-    {
-        LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
-    }
-    sessionState::for_each(boost::bind(predOnConnectionFailure, _1, channelID));
-}
-
-void LLWebRTCVoiceClient::OnConnectionEstablished(const std::string& channelID)
+void LLWebRTCVoiceClient::OnConnectionFailure(const std::string& channelID, const LLUUID& regionID)
 {
-    if (mNextAudioSession && mNextAudioSession->mChannelID == channelID)
-    {
-        mAudioSession = mNextAudioSession;
-        mNextAudioSession.reset();
-        LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
-    }
-    else if (mAudioSession && mAudioSession->mChannelID == channelID)
-    {
-        LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
-    }
-    sessionState::for_each(boost::bind(predOnConnectionEstablished, _1, channelID));
-}
-
-void LLWebRTCVoiceClient::sessionState::OnConnectionEstablished(const std::string& channelID)
-{
-    if (channelID == mPrimaryConnectionID)
+    if (gAgent.getRegion()->getRegionID() == regionID)
     {
+        if (mNextAudioSession && mNextAudioSession->mChannelID == channelID)
+        {
+            LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
+        }
+        else if (mAudioSession && mAudioSession->mChannelID == channelID)
+        {
+            LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
+        }
     }
 }
 
-void LLWebRTCVoiceClient::sessionState::OnConnectionFailure(const std::string &channelID)
+void LLWebRTCVoiceClient::OnConnectionEstablished(const std::string& channelID, const LLUUID& regionID)
 {
-    if (channelID == mPrimaryConnectionID)
+    if (gAgent.getRegion()->getRegionID() == regionID)
     {
-        LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN);
+        if (mNextAudioSession && mNextAudioSession->mChannelID == channelID)
+        {
+            mAudioSession = mNextAudioSession;
+            mNextAudioSession.reset();
+            LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
+        }
+        else if (mAudioSession && mAudioSession->mChannelID == channelID)
+        {
+            LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN);
+        }
     }
 }
 
@@ -457,6 +438,7 @@ void LLWebRTCVoiceClient::idle(void* user_data)
 
 void LLWebRTCVoiceClient::sessionState::processSessionStates()
 {
+
     auto iter = mSessions.begin();
     while (iter != mSessions.end())
     {
@@ -473,10 +455,20 @@ void LLWebRTCVoiceClient::sessionState::processSessionStates()
 
 bool LLWebRTCVoiceClient::sessionState::processConnectionStates()
 {
-    std::list<connectionPtr_t>::iterator iter = mWebRTCConnections.begin();
 
+    // Estate voice requires connection to neighboring regions.
+    std::set<LLUUID> neighbor_ids = LLWebRTCVoiceClient::getInstance()->getNeighboringRegions();
+
+    std::list<connectionPtr_t>::iterator iter = mWebRTCConnections.begin();
     while (iter != mWebRTCConnections.end())
     {
+        if (neighbor_ids.find(iter->get()->getRegionID()) == neighbor_ids.end())
+        {
+            // shut down connections to neighbors that are too far away.
+            iter->get()->shutDown();
+        }
+        neighbor_ids.erase(iter->get()->getRegionID());
+
         if (!iter->get()->connectionStateMachine())
         {
             iter = mWebRTCConnections.erase(iter);
@@ -486,6 +478,15 @@ bool LLWebRTCVoiceClient::sessionState::processConnectionStates()
             ++iter;
         }
     }
+
+    // add new connections for new neighbors
+    if (mSessionType == SESSION_TYPE_ESTATE)
+    {
+        for (auto &neighbor : neighbor_ids)
+        {
+            mWebRTCConnections.emplace_back(new LLVoiceWebRTCConnection(neighbor, INVALID_PARCEL_ID, mChannelID));
+        }
+    }
     return !mWebRTCConnections.empty();
 }
 
@@ -505,26 +506,33 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
             {
                 continue;
             }
-
-            if (mVoiceEnabled && (!mAudioSession || mAudioSession->isSpatial()) && !mNextAudioSession)
+            bool voiceEnabled = mVoiceEnabled && regionp->isVoiceEnabled();
+            if ((!mAudioSession || mAudioSession->isSpatial()) && !mNextAudioSession)
             {
                 // check to see if parcel changed.
-                std::string channelID = regionp->getRegionID().asString();
+                std::string channelID = "Estate";
+                S32         parcel_local_id = INVALID_PARCEL_ID;
 
-                LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-                S32       parcel_local_id = INVALID_PARCEL_ID;
-                if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID)
+                if (voiceEnabled)
                 {
-                    if (!parcel->getParcelFlagAllowVoice())
-                    {
-                        channelID.clear();
-                    }
-                    else if (!parcel->getParcelFlagUseEstateVoiceChannel())
+                    LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+                    if (parcel && parcel->getLocalID() != INVALID_PARCEL_ID)
                     {
-                        parcel_local_id = parcel->getLocalID();
-                        channelID += "-" + std::to_string(parcel->getLocalID());
+                        if (!parcel->getParcelFlagAllowVoice())
+                        {
+                            channelID.clear();
+                        }
+                        else if (!parcel->getParcelFlagUseEstateVoiceChannel())
+                        {
+                            parcel_local_id = parcel->getLocalID();
+                            channelID       = regionp->getRegionID().asString() + "-" + std::to_string(parcel->getLocalID());
+                        }
                     }
                 }
+                else
+                {
+                    channelID.clear();
+                }
                 
                 if ((mNextAudioSession && channelID != mNextAudioSession->mChannelID) ||
                     (!mAudioSession && !channelID.empty()) || 
@@ -532,9 +540,13 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
                 {
                     setSpatialChannel(channelID, "", parcel_local_id);
                 }
+            }
+            else
+            {
+
             }
             sessionState::processSessionStates();
-            if (mVoiceEnabled)
+            if (voiceEnabled)
             {
                 updatePosition();
                 sendPositionAndVolumeUpdate(true);
@@ -766,26 +778,6 @@ void LLWebRTCVoiceClient::sendPositionAndVolumeUpdate(bool force)
     if (mSpatialCoordsDirty || force)
     {
         Json::Value   spatial = Json::objectValue;
-        LLVector3d earPosition;
-        LLQuaternion  earRot;
-        switch (mEarLocation)
-        {
-            case earLocCamera:
-            default:
-                earPosition = mCameraPosition;
-                earRot      = mCameraRot;
-                break;
-
-            case earLocAvatar:
-                earPosition = mAvatarPosition;
-                earRot      = mAvatarRot;
-                break;
-
-            case earLocMixed:
-                earPosition = mAvatarPosition;
-                earRot      = mCameraRot;
-                break;
-        }
 
         spatial["sp"]   = Json::objectValue;
         spatial["sp"]["x"] = (int) (mAvatarPosition[0] * 100);
@@ -798,14 +790,14 @@ void LLWebRTCVoiceClient::sendPositionAndVolumeUpdate(bool force)
         spatial["sh"]["w"] = (int) (mAvatarRot[3] * 100);
 
         spatial["lp"]   = Json::objectValue;
-        spatial["lp"]["x"] = (int) (earPosition[0] * 100);
-        spatial["lp"]["y"] = (int) (earPosition[1] * 100);
-        spatial["lp"]["z"] = (int) (earPosition[2] * 100);
+        spatial["lp"]["x"] = (int) (mListenerPosition[0] * 100);
+        spatial["lp"]["y"] = (int) (mListenerPosition[1] * 100);
+        spatial["lp"]["z"] = (int) (mListenerPosition[2] * 100);
         spatial["lh"]      = Json::objectValue;
-        spatial["lh"]["x"] = (int) (earRot[0] * 100);
-        spatial["lh"]["y"] = (int) (earRot[1] * 100);
-        spatial["lh"]["z"] = (int) (earRot[2] * 100);
-        spatial["lh"]["w"] = (int) (earRot[3] * 100);
+        spatial["lh"]["x"] = (int) (mListenerRot[0] * 100);
+        spatial["lh"]["y"] = (int) (mListenerRot[1] * 100);
+        spatial["lh"]["z"] = (int) (mListenerRot[2] * 100);
+        spatial["lh"]["w"] = (int) (mListenerRot[3] * 100);
 
         mSpatialCoordsDirty = false;
         if (force || (uint_audio_level != mAudioLevel))
@@ -1479,79 +1471,120 @@ std::string LLWebRTCVoiceClient::getAudioSessionURI()
 /////////////////////////////
 // Sending updates of current state
 
-void LLWebRTCVoiceClient::enforceTether(void)
+void LLWebRTCVoiceClient::enforceTether()
 {
-	LLVector3d tethered	= mCameraRequestedPosition;
+	LLVector3d tethered	= mListenerRequestedPosition;
 
 	// constrain 'tethered' to within 50m of mAvatarPosition.
 	{
-		F32 max_dist = 50.0f;
-		LLVector3d camera_offset = mCameraRequestedPosition - mAvatarPosition;
+		LLVector3d camera_offset = mListenerRequestedPosition - mAvatarPosition;
 		F32 camera_distance = (F32)camera_offset.magVec();
-		if(camera_distance > max_dist)
+		if(camera_distance > MAX_AUDIO_DIST)
 		{
 			tethered = mAvatarPosition + 
-				(max_dist / camera_distance) * camera_offset;
+				(MAX_AUDIO_DIST / camera_distance) * camera_offset;
 		}
 	}
 	
-	if(dist_vec_squared(mCameraPosition, tethered) > 0.01)
+	if(dist_vec_squared(mListenerPosition, tethered) > 0.01)
 	{
-		mCameraPosition = tethered;
+        mListenerPosition   = tethered;
 		mSpatialCoordsDirty = true;
 	}
 }
 
-void LLWebRTCVoiceClient::updatePosition(void)
+void LLWebRTCVoiceClient::updateNeighboringRegions()
 {
+    static const std::vector<LLVector3d> neighbors {LLVector3d(0.0f, 1.0f, 0.0f),  LLVector3d(0.707f, 0.707f, 0.0f),
+                                                    LLVector3d(1.0f, 0.0f, 0.0f),  LLVector3d(0.707f, -0.707f, 0.0f),
+                                                    LLVector3d(0.0f, -1.0f, 0.0f), LLVector3d(-0.707f, -0.707f, 0.0f),
+                                                    LLVector3d(-1.0f, 0.0f, 0.0f), LLVector3d(-0.707f, 0.707f, 0.0f)};
 
+    // Estate voice requires connection to neighboring regions.
+    mNeighboringRegions.clear();
+
+    mNeighboringRegions.insert(gAgent.getRegion()->getRegionID());
+
+    // base off of speaker position as it'll move more slowly than camera position.
+    // Once we have hysteresis, we may be able to track off of speaker and camera position at 50m
+    // TODO: Add hysteresis so we don't flip-flop connections to neighbors
+    LLVector3d speaker_pos = LLWebRTCVoiceClient::getInstance()->getSpeakerPosition();
+    for (auto &neighbor_pos : neighbors)
+    {
+        // include every region within 100m (2*MAX_AUDIO_DIST) to deal witht he fact that the camera
+        // can stray 50m away from the avatar.
+        LLViewerRegion *neighbor = LLWorld::instance().getRegionFromPosGlobal(speaker_pos + 2 * MAX_AUDIO_DIST * neighbor_pos);
+        if (neighbor && !neighbor->getRegionID().isNull())
+        {
+            mNeighboringRegions.insert(neighbor->getRegionID());
+        }
+    }
+}
+
+void LLWebRTCVoiceClient::updatePosition(void)
+{
 	LLViewerRegion *region = gAgent.getRegion();
 	if(region && isAgentAvatarValid())
 	{
-		LLVector3d pos;
-        LLQuaternion qrot;
+        LLVector3d avatar_pos = gAgentAvatarp->getPositionGlobal();
+        LLQuaternion avatar_qrot = gAgentAvatarp->getRootJoint()->getWorldRotation();
+
+		avatar_pos += LLVector3d(0.f, 0.f, 1.f); // bump it up to head height
 		
 		// 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
-		pos = gAgent.getRegion()->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
-		
-		LLWebRTCVoiceClient::getInstance()->setCameraPosition(
-															 pos,				// position
-															 LLVector3::zero, 	// velocity
-                                                             LLViewerCamera::getInstance()->getQuaternion()); // rotation matrix
-		
-		// Send the current avatar position to the voice code
-        qrot = gAgentAvatarp->getRootJoint()->getWorldRotation();
-		pos = gAgentAvatarp->getPositionGlobal();
+        LLVector3d   earPosition;
+        LLQuaternion earRot;
+        switch (mEarLocation)
+        {
+            case earLocCamera:
+            default:
+                earPosition = region->getPosGlobalFromRegion(LLViewerCamera::getInstance()->getOrigin());
+                earRot      = LLViewerCamera::getInstance()->getQuaternion();
+                break;
 
-		// TODO: Can we get the head offset from outside the LLVOAvatar?
-		//			pos += LLVector3d(mHeadOffset);
-		pos += LLVector3d(0.f, 0.f, 1.f);
+            case earLocAvatar:
+                earPosition = mAvatarPosition;
+                earRot      = mAvatarRot;
+                break;
+
+            case earLocMixed:
+                earPosition = mAvatarPosition;
+                earRot      = LLViewerCamera::getInstance()->getQuaternion();
+                break;
+        }		
+		setListenerPosition(earPosition,      // position
+				            LLVector3::zero,  // velocity
+                            earRot);          // rotation matrix
 		
-		LLWebRTCVoiceClient::getInstance()->setAvatarPosition(
-															 pos,				// position
-															 LLVector3::zero, 	// velocity
-															 qrot);				// rotation matrix
+		setAvatarPosition(
+			avatar_pos,			// position
+			LLVector3::zero, 	// velocity
+			avatar_qrot);		// rotation matrix
 
         enforceTether();
+
+        if (mSpatialCoordsDirty)
+        {
+            updateNeighboringRegions();
+        }
 	}
 }
 
-void LLWebRTCVoiceClient::setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot)
+void LLWebRTCVoiceClient::setListenerPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot)
 {
-	mCameraRequestedPosition = position;
+
+	mListenerPosition = position;
 	
-	if(mCameraVelocity != velocity)
+	if(mListenerVelocity != velocity)
 	{
-		mCameraVelocity = velocity;
+		mListenerVelocity = velocity;
 		mSpatialCoordsDirty = true;
 	}
 	
-	if(mCameraRot != rot)
+	if(mListenerRot != rot)
 	{
-		mCameraRot = rot;
+		mListenerRot = rot;
 		mSpatialCoordsDirty = true;
 	}
 }
@@ -1925,7 +1958,8 @@ LLWebRTCVoiceClient::sessionState::sessionState() :
     mErrorStatusCode(0),
     mVolumeDirty(false),
     mMuteDirty(false),
-    mParticipantsChanged(false)
+    mParticipantsChanged(false),
+    mShuttingDown(false)
 {
 }
 
@@ -2047,7 +2081,8 @@ LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::findP2PSession(const
 
 
 void LLWebRTCVoiceClient::sessionState::shutdownAllConnections()
-{ 
+{
+    mShuttingDown = true;
     for (auto &&connection : mWebRTCConnections)
     {
         connection->shutDown();
@@ -2686,7 +2721,7 @@ void LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure(std::string url, i
             boost::bind(&LLVoiceWebRTCConnection::OnVoiceConnectionRequestFailure, this, url, retries - 1, body, _1));
         return;
     }
-    LL_WARNS("Voice") << "Unable to connect voice." << result << LL_ENDL;
+    LL_WARNS("Voice") << "Unable to connect voice." << body << " RESULT: " << result << LL_ENDL;
     setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);       
     mOutstandingRequests--;
 }
@@ -2753,7 +2788,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
             mWebRTCAudioInterface->setMute(mMuted);
             mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
             mWebRTCAudioInterface->setSendVolume(mMicGain);
-            LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID);
+            LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
             setVoiceConnectionState(VOICE_STATE_SESSION_UP);
         }
         break;
@@ -2767,7 +2802,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
         }
 
         case VOICE_STATE_SESSION_RETRY:
-            LLWebRTCVoiceClient::getInstance()->OnConnectionFailure(mChannelID);
+            LLWebRTCVoiceClient::getInstance()->OnConnectionFailure(mChannelID, mRegionID);
             setVoiceConnectionState(VOICE_STATE_DISCONNECT);
             break;
         break;
@@ -2903,10 +2938,19 @@ void LLVoiceWebRTCConnection::OnVoiceDisconnectionRequestFailure(std::string url
 
 void LLVoiceWebRTCConnection::setMuteMic(bool muted)
 {
-    mMuted = true;
+    mMuted = muted;
     if (mWebRTCAudioInterface)
     {
-        mWebRTCAudioInterface->setMute(muted);
+        LLViewerRegion *regionp = gAgent.getRegion();
+        if (regionp && mRegionID == regionp->getRegionID())
+        {
+            mWebRTCAudioInterface->setMute(muted);
+        }
+        else
+        {
+            // always mute to regions the agent isn't on, to prevent echo.
+            mWebRTCAudioInterface->setMute(true);
+        }
     }
 }
 
diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h
index 1e8ecdf5c2..9b8372cba7 100644
--- a/indra/newview/llvoicewebrtc.h
+++ b/indra/newview/llvoicewebrtc.h
@@ -242,8 +242,8 @@ public:
     void userAuthorized(const std::string &user_id, const LLUUID &agentID) override {};
 
 
-	void OnConnectionEstablished(const std::string& channelID);
-    void OnConnectionFailure(const std::string &channelID);
+	void OnConnectionEstablished(const std::string& channelID, const LLUUID& regionID);
+    void OnConnectionFailure(const std::string &channelID, const LLUUID& regionID);
     void sendPositionAndVolumeUpdate(bool force);
     void updateOwnVolume();
 	
@@ -312,6 +312,12 @@ public:
         typedef boost::weak_ptr<sessionState> wptr_t;
 
         typedef boost::function<void(const ptr_t &)> sessionFunc_t;
+        typedef enum e_session_type
+        {
+            SESSION_TYPE_ESTATE = 1,
+            SESSION_TYPE_PARCEL,
+            SESSION_TYPE_P2P
+        } ESessionType;
 
         static ptr_t createSession(const std::string& channelID, S32 parcel_local_id);
 		~sessionState();
@@ -334,9 +340,6 @@ public:
 
         bool processConnectionStates();
 
-		void OnConnectionEstablished(const std::string &channelID);
-        void OnConnectionFailure(const std::string &channelID);
-
 		void sendData(const std::string &data);
         
         void setMuteMic(bool muted);
@@ -351,12 +354,7 @@ public:
 
 		bool isSpatial() { return mSessionType == SESSION_TYPE_ESTATE || mSessionType == SESSION_TYPE_PARCEL; }
 
-    typedef enum e_session_type
-        {
-            SESSION_TYPE_ESTATE                = 1,
-            SESSION_TYPE_PARCEL,
-            SESSION_TYPE_P2P
-        } ESessionType;
+        ESessionType getSessionType() { return mSessionType; }
 
 		std::string mHandle;
 		std::string mGroupHandle;
@@ -378,6 +376,7 @@ public:
 		bool		mIncoming;
 		bool		mVoiceActive;
 		bool		mReconnect;	// Whether we should try to reconnect to this session if it's dropped
+        bool        mShuttingDown;
 
 		// Set to true when the volume/mute state of someone in the participant list changes.
 		// The code will have to walk the list to find the changed participant(s).
@@ -417,8 +416,6 @@ public:
 	// Private Member Functions
 	//////////////////////////////////////////////////////
 
-    static void predOnConnectionEstablished(const LLWebRTCVoiceClient::sessionStatePtr_t &session, std::string channelID);
-    static void predOnConnectionFailure(const LLWebRTCVoiceClient::sessionStatePtr_t &session, std::string channelID);
     static void predSendData(const LLWebRTCVoiceClient::sessionStatePtr_t &session, const std::string& spatial_data, const std::string& volume_data);
     static void predUpdateOwnVolume(const LLWebRTCVoiceClient::sessionStatePtr_t &session, F32 audio_level);
     static void predSetMuteMic(const LLWebRTCVoiceClient::sessionStatePtr_t &session, bool mute);
@@ -459,10 +456,13 @@ public:
 	/////////////////////////////
 	// Sending updates of current state
 	void updatePosition(void);
-	void setCameraPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot);
+	void setListenerPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot);
 	void setAvatarPosition(const LLVector3d &position, const LLVector3 &velocity, const LLQuaternion &rot);
 	bool channelFromRegion(LLViewerRegion *region, std::string &name);
 
+	LLVector3d getListenerPosition() { return mListenerPosition; }
+    LLVector3d getSpeakerPosition() { return mAvatarPosition; }
+
 	void setEarLocation(S32 loc);
 
 	
@@ -613,23 +613,28 @@ private:
 	std::string displayNameFromAvatar(LLVOAvatar *avatar);
 	
 
-	bool inSpatialChannel(void);
+	bool inSpatialChannel();
 	std::string getAudioSessionURI();
 			
     void setHidden(bool hidden) override; //virtual
 
-	void enforceTether(void);
+	void enforceTether();
+
+	void updateNeighboringRegions();
+    std::set<LLUUID> getNeighboringRegions() { return mNeighboringRegions; }
 	
 	bool		mSpatialCoordsDirty;
 	
-	LLVector3d	mCameraPosition;
-	LLVector3d	mCameraRequestedPosition;
-	LLVector3	mCameraVelocity;
-	LLQuaternion mCameraRot;
+	LLVector3d	mListenerPosition;
+	LLVector3d	mListenerRequestedPosition;
+	LLVector3	mListenerVelocity;
+	LLQuaternion mListenerRot;
 
 	LLVector3d	mAvatarPosition;
 	LLVector3	mAvatarVelocity;
 	LLQuaternion mAvatarRot;
+
+	std::set<LLUUID> mNeighboringRegions; // includes current region
 	
 	bool		mMuteMic;
 	bool		mMuteMicDirty;
@@ -763,6 +768,8 @@ class LLVoiceWebRTCConnection :
     void setMicGain(F32 volume);
     void setSpeakerVolume(F32 volume);
 
+	LLUUID getRegionID() { return mRegionID; }
+
 	void shutDown()
 	{ 
 		LLMutexLock lock(&mVoiceStateMutex);
-- 
cgit v1.2.3