diff options
-rw-r--r-- | indra/newview/llvoicewebrtc.cpp | 300 | ||||
-rw-r--r-- | 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()) || @@ -533,8 +541,12 @@ 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); |