diff options
author | Erik Kundiman <erik@megapahit.org> | 2024-08-19 19:59:03 +0800 |
---|---|---|
committer | Erik Kundiman <erik@megapahit.org> | 2024-08-19 19:59:03 +0800 |
commit | 495f103000137b3288eaa05a4298fd33ceb3c2dc (patch) | |
tree | 19b79a5cb33275a874d24e923a04de7b9657401b /indra/newview/llvoicewebrtc.cpp | |
parent | b7a79709003b1f7f0451ba577576040fc03e50f9 (diff) | |
parent | 0f3ffb0fad721740f20ed5c7a74f4ceade6d46b6 (diff) |
Merge remote-tracking branch 'secondlife/release/2024.06-atlasaurus' into 2024.06-atlasaurus
Diffstat (limited to 'indra/newview/llvoicewebrtc.cpp')
-rw-r--r-- | indra/newview/llvoicewebrtc.cpp | 180 |
1 files changed, 126 insertions, 54 deletions
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 617981c3aa..679df094cf 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -239,11 +239,26 @@ LLWebRTCVoiceClient::LLWebRTCVoiceClient() : LLWebRTCVoiceClient::~LLWebRTCVoiceClient() { +} + +void LLWebRTCVoiceClient::cleanupSingleton() +{ if (mAvatarNameCacheConnection.connected()) { mAvatarNameCacheConnection.disconnect(); } + sShuttingDown = true; + if (mSession) + { + mSession->shutdownAllConnections(); + } + if (mNextSession) + { + mNextSession->shutdownAllConnections(); + } + cleanUp(); + sessionState::clearSessions(); } //--------------------------------------------------- @@ -256,6 +271,7 @@ void LLWebRTCVoiceClient::init(LLPumpIO* pump) mWebRTCDeviceInterface = llwebrtc::getDeviceInterface(); mWebRTCDeviceInterface->setDevicesObserver(this); mMainQueue = LL::WorkQueue::getInstance("mainloop"); + refreshDeviceLists(); } void LLWebRTCVoiceClient::terminate() @@ -460,6 +476,7 @@ void LLWebRTCVoiceClient::voiceConnectionCoro() // Could help with voice updates making for smoother // voice when we're busy. llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); + if (sShuttingDown) return; // 'this' migh already be invalid bool voiceEnabled = mVoiceEnabled; if (!isAgentAvatarValid()) @@ -623,7 +640,7 @@ void LLWebRTCVoiceClient::clearCaptureDevices() void LLWebRTCVoiceClient::addCaptureDevice(const LLVoiceDevice& device) { - LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL; + LL_INFOS("Voice") << "Voice Capture Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL; mCaptureDevices.push_back(device); } @@ -656,6 +673,10 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices, const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices) { + if (sShuttingDown) + { + return; + } LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice"); std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); @@ -688,7 +709,7 @@ void LLWebRTCVoiceClient::clearRenderDevices() void LLWebRTCVoiceClient::addRenderDevice(const LLVoiceDevice& device) { - LL_DEBUGS("Voice") << "display: '" << device.display_name << "' device: '" << device.full_name << "'" << LL_ENDL; + LL_INFOS("Voice") << "Voice Render Device: '" << device.display_name << "' (" << device.full_name << ")" << LL_ENDL; mRenderDevices.push_back(device); } @@ -1256,7 +1277,7 @@ void LLWebRTCVoiceClient::sessionState::removeParticipant(const LLWebRTCVoiceCli LLWebRTCVoiceClient::getInstance()->notifyParticipantObservers(); } } - if (mHangupOnLastLeave && (participantID != gAgentID) && (mParticipantsByUUID.size() <= 1)) + if (mHangupOnLastLeave && (participantID != gAgentID) && (mParticipantsByUUID.size() <= 1) && LLWebRTCVoiceClient::instanceExists()) { LLWebRTCVoiceClient::getInstance()->notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL); } @@ -1707,7 +1728,7 @@ void LLWebRTCVoiceClient::predSetUserMute(const LLWebRTCVoiceClient::sessionStat //------------------------------------------------------------------------ // Sessions -std::map<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> LLWebRTCVoiceClient::sessionState::mSessions; +std::map<std::string, LLWebRTCVoiceClient::sessionState::ptr_t> LLWebRTCVoiceClient::sessionState::sSessions; LLWebRTCVoiceClient::sessionState::sessionState() : @@ -1794,13 +1815,19 @@ void LLWebRTCVoiceClient::sessionState::addSession( const std::string & channelID, LLWebRTCVoiceClient::sessionState::ptr_t& session) { - mSessions[channelID] = session; + sSessions[channelID] = session; } LLWebRTCVoiceClient::sessionState::~sessionState() { LL_DEBUGS("Voice") << "Destroying session CHANNEL=" << mChannelID << LL_ENDL; + if (!mShuttingDown) + { + shutdownAllConnections(); + } + mWebRTCConnections.clear(); + removeAllParticipants(); } @@ -1810,8 +1837,8 @@ LLWebRTCVoiceClient::sessionState::ptr_t LLWebRTCVoiceClient::sessionState::matc sessionStatePtr_t result; // *TODO: My kingdom for a lambda! - std::map<std::string, ptr_t>::iterator it = mSessions.find(channel_id); - if (it != mSessions.end()) + std::map<std::string, ptr_t>::iterator it = sSessions.find(channel_id); + if (it != sSessions.end()) { result = (*it).second; } @@ -1820,17 +1847,17 @@ LLWebRTCVoiceClient::sessionState::ptr_t LLWebRTCVoiceClient::sessionState::matc void LLWebRTCVoiceClient::sessionState::for_each(sessionFunc_t func) { - std::for_each(mSessions.begin(), mSessions.end(), boost::bind(for_eachPredicate, _1, func)); + std::for_each(sSessions.begin(), sSessions.end(), boost::bind(for_eachPredicate, _1, func)); } void LLWebRTCVoiceClient::sessionState::reapEmptySessions() { std::map<std::string, ptr_t>::iterator iter; - for (iter = mSessions.begin(); iter != mSessions.end();) + for (iter = sSessions.begin(); iter != sSessions.end();) { if (iter->second->isEmpty()) { - iter = mSessions.erase(iter); + iter = sSessions.erase(iter); } else { @@ -1876,6 +1903,11 @@ LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::addSession(const std } } +void LLWebRTCVoiceClient::sessionState::clearSessions() +{ + sSessions.clear(); +} + LLWebRTCVoiceClient::sessionStatePtr_t LLWebRTCVoiceClient::findP2PSession(const LLUUID &agent_id) { sessionStatePtr_t result = sessionState::matchSessionByChannelID(agent_id.asString()); @@ -1915,14 +1947,14 @@ void LLWebRTCVoiceClient::sessionState::processSessionStates() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE - auto iter = mSessions.begin(); - while (iter != mSessions.end()) + auto iter = sSessions.begin(); + while (iter != sSessions.end()) { if (!iter->second->processConnectionStates() && iter->second->mShuttingDown) { // if the connections associated with a session are gone, // and this session is shutting down, remove it. - iter = mSessions.erase(iter); + iter = sSessions.erase(iter); } else { @@ -1967,8 +1999,8 @@ bool LLWebRTCVoiceClient::estateSessionState::processConnectionStates() for (auto &connection : mWebRTCConnections) { - boost::shared_ptr<LLVoiceWebRTCSpatialConnection> spatialConnection = - boost::static_pointer_cast<LLVoiceWebRTCSpatialConnection>(connection); + std::shared_ptr<LLVoiceWebRTCSpatialConnection> spatialConnection = + std::static_pointer_cast<LLVoiceWebRTCSpatialConnection>(connection); LLUUID regionID = spatialConnection.get()->getRegionID(); @@ -2123,8 +2155,10 @@ LLVoiceWebRTCConnection::LLVoiceWebRTCConnection(const LLUUID ®ionID, const s mOutstandingRequests(0), mChannelID(channelID), mRegionID(regionID), + mPrimary(true), mRetryWaitPeriod(0) { + // retries wait a short period...randomize it so // all clients don't try to reconnect at once. mRetryWaitSecs = ((F32) rand() / (RAND_MAX)) + 0.5; @@ -2190,47 +2224,47 @@ void LLVoiceWebRTCConnection::processIceUpdates() { mOutstandingRequests++; LLCoros::getInstance()->launch("LLVoiceWebRTCConnection::processIceUpdatesCoro", - boost::bind(&LLVoiceWebRTCConnection::processIceUpdatesCoro, this)); + boost::bind(&LLVoiceWebRTCConnection::processIceUpdatesCoro, this->shared_from_this())); } // Ice candidates may be streamed in before or after the SDP offer is available (see below) // This function determines whether candidates are available to send to the Secondlife WebRTC // server via the simulator. If so, and there are no more candidates, this code // will make the cap call to the server sending up the ICE candidates. -void LLVoiceWebRTCConnection::processIceUpdatesCoro() +void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE - if (mShutDown || LLWebRTCVoiceClient::isShuttingDown()) + if (connection->mShutDown || LLWebRTCVoiceClient::isShuttingDown()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } - //bool iceCompleted = false; + bool iceCompleted = false; LLSD body; - if (!mIceCandidates.empty() || mIceCompleted) + if (!connection->mIceCandidates.empty() || connection->mIceCompleted) { - LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(connection->mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for ice gathering; waiting " << LL_ENDL; - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } std::string url = regionp->getCapability("VoiceSignalingRequest"); if (url.empty()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } LL_DEBUGS("Voice") << "region ready to complete voice signaling; url=" << url << LL_ENDL; - if (!mIceCandidates.empty()) + if (!connection->mIceCandidates.empty()) { LLSD candidates = LLSD::emptyArray(); - for (auto &ice_candidate : mIceCandidates) + for (auto &ice_candidate : connection->mIceCandidates) { LLSD body_candidate; body_candidate["sdpMid"] = ice_candidate.mSdpMid; @@ -2239,18 +2273,18 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() candidates.append(body_candidate); } body["candidates"] = candidates; - mIceCandidates.clear(); + connection->mIceCandidates.clear(); } - else if (mIceCompleted) + else if (connection->mIceCompleted) { LLSD body_candidate; body_candidate["completed"] = true; body["candidate"] = body_candidate; - //iceCompleted = mIceCompleted; - mIceCompleted = false; + iceCompleted = connection->mIceCompleted; + connection->mIceCompleted = false; } - body["viewer_session"] = mViewerSession; + body["viewer_session"] = connection->mViewerSession; body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE; LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( @@ -2265,7 +2299,7 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() if (LLWebRTCVoiceClient::isShuttingDown()) { - mOutstandingRequests--; + connection->mOutstandingRequests--; return; } @@ -2275,10 +2309,10 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro() if (!status) { // couldn't trickle the candidates, so restart the session. - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); } } - mOutstandingRequests--; + connection->mOutstandingRequests--; } @@ -2370,6 +2404,12 @@ void LLVoiceWebRTCConnection::OnPeerConnectionClosed() setVoiceConnectionState(VOICE_STATE_CLOSED); mOutstandingRequests--; } + else if (LLWebRTCVoiceClient::isShuttingDown()) + { + // disconnect was initialized by llwebrtc::terminate() instead of connectionStateMachine + LL_INFOS("Voice") << "Peer connection has closed, but state is " << mVoiceConnectionState << LL_ENDL; + setVoiceConnectionState(VOICE_STATE_CLOSED); + } }); } @@ -2424,31 +2464,31 @@ void LLVoiceWebRTCConnection::sendData(const std::string &data) // Tell the simulator that we're shutting down a voice connection. // The simulator will pass this on to the Secondlife WebRTC server. -void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() +void LLVoiceWebRTCConnection::breakVoiceConnectionCoro(connectionPtr_t connection) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE LL_DEBUGS("Voice") << "Disconnecting voice." << LL_ENDL; - if (mWebRTCDataInterface) + if (connection->mWebRTCDataInterface) { - mWebRTCDataInterface->unsetDataObserver(this); - mWebRTCDataInterface = nullptr; + connection->mWebRTCDataInterface->unsetDataObserver(connection.get()); + connection->mWebRTCDataInterface = nullptr; } - mWebRTCAudioInterface = nullptr; - LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID); + connection->mWebRTCAudioInterface = nullptr; + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(connection->mRegionID); if (!regionp || !regionp->capabilitiesReceived()) { LL_DEBUGS("Voice") << "no capabilities for voice provisioning; waiting " << LL_ENDL; - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); - mOutstandingRequests--; + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->mOutstandingRequests--; return; } std::string url = regionp->getCapability("ProvisionVoiceAccountRequest"); if (url.empty()) { - setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); - mOutstandingRequests--; + connection->setVoiceConnectionState(VOICE_STATE_SESSION_RETRY); + connection->mOutstandingRequests--; return; } @@ -2457,7 +2497,7 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() LLVoiceWebRTCStats::getInstance()->provisionAttemptStart(); LLSD body; body["logout"] = true; - body["viewer_session"] = mViewerSession; + body["viewer_session"] = connection->mViewerSession; body["voice_server_type"] = WEBRTC_VOICE_SERVER_TYPE; LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter( @@ -2468,15 +2508,19 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro() httpOpts->setWantHeaders(true); - mOutstandingRequests++; + connection->mOutstandingRequests++; // tell the server to shut down the connection as a courtesy. // shutdownConnection will drop the WebRTC connection which will // also shut things down. LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts); - mOutstandingRequests--; - setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + connection->mOutstandingRequests--; + + if (connection->getVoiceConnectionState() == VOICE_STATE_WAIT_FOR_EXIT) + { + connection->setVoiceConnectionState(VOICE_STATE_SESSION_EXIT); + } } // Tell the simulator to tell the Secondlife WebRTC server that we want a voice @@ -2660,7 +2704,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() // VOICE_STATE_SESSION_ESTABLISHED via a callback on a webrtc thread. setVoiceConnectionState(VOICE_STATE_CONNECTION_WAIT); LLCoros::getInstance()->launch("LLVoiceWebRTCConnection::requestVoiceConnectionCoro", - boost::bind(&LLVoiceWebRTCConnection::requestVoiceConnectionCoro, this)); + boost::bind(&LLVoiceWebRTCConnection::requestVoiceConnectionCoro, this->shared_from_this())); break; case VOICE_STATE_CONNECTION_WAIT: @@ -2710,6 +2754,17 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { mRetryWaitPeriod = 0; mRetryWaitSecs = ((F32) rand() / (RAND_MAX)) + 0.5; + LLUUID agentRegionID; + if (isSpatial() && gAgent.getRegion()) + { + + bool primary = (mRegionID == gAgent.getRegion()->getRegionID()); + if (primary != mPrimary) + { + mPrimary = primary; + sendJoin(); + } + } // we'll stay here as long as the session remains up. if (mShutDown) @@ -2738,9 +2793,18 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() break; case VOICE_STATE_DISCONNECT: - setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); - LLCoros::instance().launch("LLVoiceWebRTCConnection::breakVoiceConnectionCoro", - boost::bind(&LLVoiceWebRTCConnection::breakVoiceConnectionCoro, this)); + if (!LLWebRTCVoiceClient::isShuttingDown()) + { + setVoiceConnectionState(VOICE_STATE_WAIT_FOR_EXIT); + LLCoros::instance().launch("LLVoiceWebRTCConnection::breakVoiceConnectionCoro", + boost::bind(&LLVoiceWebRTCConnection::breakVoiceConnectionCoro, this->shared_from_this())); + } + else + { + // llwebrtc::terminate() is already shuting down the connection. + setVoiceConnectionState(VOICE_STATE_WAIT_FOR_CLOSE); + mOutstandingRequests++; + } break; case VOICE_STATE_WAIT_FOR_EXIT: @@ -2750,7 +2814,11 @@ bool LLVoiceWebRTCConnection::connectionStateMachine() { setVoiceConnectionState(VOICE_STATE_WAIT_FOR_CLOSE); mOutstandingRequests++; - mWebRTCPeerConnectionInterface->shutdownConnection(); + if (!LLWebRTCVoiceClient::isShuttingDown()) + { + mWebRTCPeerConnectionInterface->shutdownConnection(); + } + // else was already posted by llwebrtc::terminate(). break; case VOICE_STATE_WAIT_FOR_CLOSE: break; @@ -2980,7 +3048,7 @@ void LLVoiceWebRTCConnection::sendJoin() boost::json::object root; boost::json::object join_obj; LLUUID regionID = gAgent.getRegion()->getRegionID(); - if ((regionID == mRegionID) || !isSpatial()) + if (mPrimary) { join_obj["p"] = true; } @@ -2998,6 +3066,10 @@ LLVoiceWebRTCSpatialConnection::LLVoiceWebRTCSpatialConnection(const LLUUID ® LLVoiceWebRTCConnection(regionID, channelID), mParcelLocalID(parcelLocalID) { + if (gAgent.getRegion()) + { + mPrimary = (regionID == gAgent.getRegion()->getRegionID()); + } } LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection() |