From 6ee41d60753d31d6826994731570f0ab64b92bd9 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 26 Nov 2025 18:41:30 +0200 Subject: #5018 add webrtc connection statistics --- indra/llwebrtc/llwebrtc.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++ indra/llwebrtc/llwebrtc.h | 6 +++++ indra/llwebrtc/llwebrtc_impl.h | 2 ++ 3 files changed, 59 insertions(+) (limited to 'indra/llwebrtc') diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index b9f126e511..62eadecd6f 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -1521,6 +1521,57 @@ void LLWebRTCPeerConnectionImpl::unsetDataObserver(LLWebRTCDataObserver* observe } } +class LLStatsCollectorCallback : public webrtc::RTCStatsCollectorCallback +{ +public: + typedef std::function StatsCallback; + + LLStatsCollectorCallback(StatsCallback callback) : callback_(callback) {} + + void OnStatsDelivered(const webrtc::scoped_refptr& report) override + { + if (callback_) + { + // Transform RTCStatsReport stats to simple map + LLWebRTCStatsMap stats_map; + for (const auto& stats : *report) + { + std::map stat_attributes; + + // Convert each attribute to string format + for (const auto& attribute : stats.Attributes()) + { + stat_attributes[attribute.name()] = attribute.ToString(); + } + stats_map[stats.id()] = stat_attributes; + } + callback_(stats_map); + } + } + +private: + StatsCallback callback_; +}; + +void LLWebRTCPeerConnectionImpl::gatherConnectionStats() +{ + if (!mPeerConnection) + { + return; + } + + auto stats_callback = webrtc::make_ref_counted( + [this](const LLWebRTCStatsMap& generic_stats) + { + for (auto& observer : mSignalingObserverList) + { + observer->OnStatsDelivered(generic_stats); + } + }); + + mPeerConnection->GetStats(stats_callback.get()); +} + LLWebRTCImpl * gWebRTCImpl = nullptr; LLWebRTCDeviceInterface * getDeviceInterface() { diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index 7d06b7d2b4..e76e708f0c 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -38,6 +38,7 @@ #ifndef LLWEBRTC_H #define LLWEBRTC_H +#include #include #include @@ -55,6 +56,7 @@ namespace llwebrtc { +typedef std::map> LLWebRTCStatsMap; class LLWebRTCLogCallback { @@ -240,6 +242,8 @@ class LLWebRTCSignalingObserver // Called when the data channel has been established and data // transfer can begin. virtual void OnDataChannelReady(LLWebRTCDataInterface *data_interface) = 0; + + virtual void OnStatsDelivered(const LLWebRTCStatsMap& stats_data) {} }; // LLWebRTCPeerConnectionInterface representsd a connection to a peer, @@ -273,6 +277,8 @@ class LLWebRTCPeerConnectionInterface virtual void unsetSignalingObserver(LLWebRTCSignalingObserver* observer) = 0; virtual void AnswerAvailable(const std::string &sdp) = 0; + + virtual void gatherConnectionStats() = 0; }; // The following define the dynamic linked library diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 01cfb17ced..2a00e066bd 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -648,6 +648,8 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, void enableSenderTracks(bool enable); void enableReceiverTracks(bool enable); + void gatherConnectionStats(); + protected: LLWebRTCImpl * mWebRTCImpl; -- cgit v1.3 From ec149b515c26cec64d1666df5aeb441ea052cf19 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 26 Nov 2025 19:44:20 +0200 Subject: #5018 mac build fix --- indra/llwebrtc/llwebrtc_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llwebrtc') diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 2a00e066bd..c1e909df72 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -648,7 +648,7 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, void enableSenderTracks(bool enable); void enableReceiverTracks(bool enable); - void gatherConnectionStats(); + void gatherConnectionStats() override; protected: -- cgit v1.3 From 3410a0e45ce94bf25ad91905ed31905358930f4d Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 26 Mar 2026 20:37:30 +0200 Subject: #5575 fix incoming webRTC voice audio being disrupted after editing audio settings (#5581) --- indra/llwebrtc/llwebrtc_impl.h | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llwebrtc') diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index c1e909df72..2ff85c92ee 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -343,6 +343,7 @@ public: inner_->InitRecording(); inner_->StartRecording(); } + inner_->InitPlayout(); inner_->StartPlayout(); } } -- cgit v1.3 From 7719e6c16dc182ede6ed4b766d8cec4adf8feeba Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 27 Apr 2026 14:38:49 -0700 Subject: Fix P2P text chat timeout on WebRTC regions and delay voice renegotiation on disconnect (#5706) * Fix P2P text chat timeout on WebRTC regions and delay voice renegotiation on disconnect Text chat: On WebRTC regions, getOutgoingCallInterface() returns nullptr, causing mP2PAsAdhocCall to be true for all P2P sessions including text-only IMs. This routed text chat through startP2PVoiceCoro which sent a "start p2p voice" request and waited for a server reply that never came, resulting in a 30-second session initialization timeout. Fix by gating the p2p-as-adhoc server init on mStartedAsIMCall so text-only sessions initialize immediately. WebRTC: Split kFailed and kDisconnected handling in OnConnectionChange. kFailed still renegotiates immediately. kDisconnected now waits 10 seconds before renegotiating, giving the connection time to recover on its own. Uses a sequence counter to ensure only the most recent disconnect transition can trigger renegotiation, preventing stale delayed tasks from firing early after disconnect/reconnect cycles. Co-Authored-By: Claude Opus 4.6 (1M context) * Revert im-change for not using the voice subsystem when doing a text-only IM --------- Co-authored-by: Claude Opus 4.6 (1M context) --- indra/llwebrtc/llwebrtc.cpp | 29 +++++++++++++++++++++++++++-- indra/llwebrtc/llwebrtc_impl.h | 11 +++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'indra/llwebrtc') diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 6bf38cc1f6..a286f75f42 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -811,6 +811,8 @@ LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() : mPeerConnection(nullptr), mMute(MUTE_INITIAL), mAnswerReceived(false), + mPeerConnectionState(webrtc::PeerConnectionInterface::PeerConnectionState::kNew), + mDisconnectCount(0), mPendingJobs(0) { } @@ -1237,11 +1239,15 @@ void LLWebRTCPeerConnectionImpl::OnIceGatheringChange(webrtc::PeerConnectionInte } } +static const webrtc::TimeDelta DISCONNECT_RENEGOTIATE_DELAY = webrtc::TimeDelta::Millis(10000); + // Called any time the PeerConnectionState changes. void LLWebRTCPeerConnectionImpl::OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState new_state) { RTC_LOG(LS_ERROR) << __FUNCTION__ << " Peer Connection State Change " << new_state; + mPeerConnectionState = new_state; + switch (new_state) { case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected: @@ -1257,13 +1263,32 @@ void LLWebRTCPeerConnectionImpl::OnConnectionChange(webrtc::PeerConnectionInterf break; } case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed: - case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: { for (auto &observer : mSignalingObserverList) { observer->OnRenegotiationNeeded(); } - + break; + } + case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: + { + // Wait 10 seconds before renegotiating in case the connection recovers on its own. + // Use a sequence count so that only the most recent disconnect transition can trigger + // a renegotiation, avoiding stale delayed tasks from earlier disconnect/reconnect cycles. + uint32_t disconnect_count = ++mDisconnectCount; + mWebRTCImpl->PostDelayedSignalingTask( + [this, disconnect_count]() + { + if (disconnect_count == mDisconnectCount + && mPeerConnectionState == webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected) + { + for (auto &observer : mSignalingObserverList) + { + observer->OnRenegotiationNeeded(); + } + } + }, + DISCONNECT_RENEGOTIATE_DELAY); break; } default: diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 2ff85c92ee..bd7a2e0bcf 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -480,6 +480,13 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceO mSignalingThread->PostTask(std::move(task), location); } + void PostDelayedSignalingTask(absl::AnyInvocable task, + webrtc::TimeDelta delay, + const webrtc::Location& location = webrtc::Location::Current()) + { + mSignalingThread->PostDelayedTask(std::move(task), delay, location); + } + void PostNetworkTask(absl::AnyInvocable task, const webrtc::Location& location = webrtc::Location::Current()) { @@ -676,6 +683,10 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, std::vector mDataObserverList; webrtc::scoped_refptr mDataChannel; + // connection state tracking for delayed renegotiation on disconnect + webrtc::PeerConnectionInterface::PeerConnectionState mPeerConnectionState; + uint32_t mDisconnectCount; + std::atomic mPendingJobs; }; -- cgit v1.3