summaryrefslogtreecommitdiff
path: root/indra/newview/llvoicewebrtc.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2024-08-19 19:59:03 +0800
committerErik Kundiman <erik@megapahit.org>2024-08-19 19:59:03 +0800
commit495f103000137b3288eaa05a4298fd33ceb3c2dc (patch)
tree19b79a5cb33275a874d24e923a04de7b9657401b /indra/newview/llvoicewebrtc.cpp
parentb7a79709003b1f7f0451ba577576040fc03e50f9 (diff)
parent0f3ffb0fad721740f20ed5c7a74f4ceade6d46b6 (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.cpp180
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 &regionID, 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 &reg
LLVoiceWebRTCConnection(regionID, channelID),
mParcelLocalID(parcelLocalID)
{
+ if (gAgent.getRegion())
+ {
+ mPrimary = (regionID == gAgent.getRegion()->getRegionID());
+ }
}
LLVoiceWebRTCSpatialConnection::~LLVoiceWebRTCSpatialConnection()