diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:33 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:33 +0000 |
commit | 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 (patch) | |
tree | a4f824bd33cb075dd5aa3eb5a0a94af221bbe83a /dom/media/webrtc/transport | |
parent | Adding debian version 124.0.1-1. (diff) | |
download | firefox-086c044dc34dfc0f74fbe41f4ecb402b2cd34884.tar.xz firefox-086c044dc34dfc0f74fbe41f4ecb402b2cd34884.zip |
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/webrtc/transport')
13 files changed, 394 insertions, 157 deletions
diff --git a/dom/media/webrtc/transport/nricectx.cpp b/dom/media/webrtc/transport/nricectx.cpp index f30c2734c2..7c71c0ab06 100644 --- a/dom/media/webrtc/transport/nricectx.cpp +++ b/dom/media/webrtc/transport/nricectx.cpp @@ -257,14 +257,14 @@ nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server* server) const { } NrIceCtx::NrIceCtx(const std::string& name) - : connection_state_(ICE_CTX_INIT), - gathering_state_(ICE_CTX_GATHER_INIT), - name_(name), + : name_(name), ice_controlling_set_(false), ctx_(nullptr), peer_(nullptr), ice_handler_vtbl_(nullptr), ice_handler_(nullptr), + ice_gather_handler_vtbl_(nullptr), + ice_gather_handler_(nullptr), trickle_(true), config_(), nat_(nullptr), @@ -343,13 +343,10 @@ void NrIceCtx::DestroyStream(const std::string& id) { auto it = streams_.find(id); if (it != streams_.end()) { auto preexisting_stream = it->second; + SignalConnectionStateChange(preexisting_stream, ICE_CTX_CLOSED); streams_.erase(it); preexisting_stream->Close(); } - - if (streams_.empty()) { - SetGatheringState(ICE_CTX_GATHER_INIT); - } } // Handler callbacks @@ -377,6 +374,7 @@ int NrIceCtx::stream_ready(void* obj, nr_ice_media_stream* stream) { MOZ_ASSERT(s); s->Ready(stream); + ctx->SignalConnectionStateChange(s, ICE_CTX_CONNECTED); return 0; } @@ -393,44 +391,101 @@ int NrIceCtx::stream_failed(void* obj, nr_ice_media_stream* stream) { // Streams which do not exist should never fail. MOZ_ASSERT(s); - ctx->SetConnectionState(ICE_CTX_FAILED); + if (!ctx->dumped_rlog_) { + // Do this at most once per ctx + ctx->dumped_rlog_ = true; + MOZ_MTLOG(ML_INFO, + "NrIceCtx(" << ctx->name_ << "): dumping r_log ringbuffer... "); + std::deque<std::string> logs; + RLogConnector::GetInstance()->GetAny(0, &logs); + for (auto& log : logs) { + MOZ_MTLOG(ML_INFO, log); + } + } + s->Failed(); + ctx->SignalConnectionStateChange(s, ICE_CTX_FAILED); return 0; } -int NrIceCtx::ice_checking(void* obj, nr_ice_peer_ctx* pctx) { - MOZ_MTLOG(ML_DEBUG, "ice_checking called"); +int NrIceCtx::stream_checking(void* obj, nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_DEBUG, "stream_checking called"); + MOZ_ASSERT(!stream->local_stream); + MOZ_ASSERT(!stream->obsolete); // Get the ICE ctx NrIceCtx* ctx = static_cast<NrIceCtx*>(obj); + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); - ctx->SetConnectionState(ICE_CTX_CHECKING); + MOZ_ASSERT(s); + if (!s->AnyGenerationIsConnected()) { + // the checking state only applies if we aren't connected + ctx->SignalConnectionStateChange(s, ICE_CTX_CHECKING); + } return 0; } -int NrIceCtx::ice_connected(void* obj, nr_ice_peer_ctx* pctx) { - MOZ_MTLOG(ML_DEBUG, "ice_connected called"); +int NrIceCtx::stream_disconnected(void* obj, nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_DEBUG, "stream_disconnected called"); + MOZ_ASSERT(!stream->local_stream); + MOZ_ASSERT(!stream->obsolete); // Get the ICE ctx NrIceCtx* ctx = static_cast<NrIceCtx*>(obj); + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); - // This is called even on failed contexts. - if (ctx->connection_state() != ICE_CTX_FAILED) { - ctx->SetConnectionState(ICE_CTX_CONNECTED); - } + MOZ_ASSERT(s); + ctx->SignalConnectionStateChange(s, ICE_CTX_DISCONNECTED); return 0; } -int NrIceCtx::ice_disconnected(void* obj, nr_ice_peer_ctx* pctx) { - MOZ_MTLOG(ML_DEBUG, "ice_disconnected called"); +int NrIceCtx::stream_gathering(void* obj, nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_DEBUG, "stream_gathering called"); + MOZ_ASSERT(!stream->local_stream); + MOZ_ASSERT(!stream->obsolete); + + // Get the ICE ctx + NrIceCtx* ctx = static_cast<NrIceCtx*>(obj); + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); + + MOZ_ASSERT(s); + + s->OnGatheringStarted(stream); + return 0; +} + +int NrIceCtx::stream_gathered(void* obj, nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_DEBUG, "stream_gathered called"); + MOZ_ASSERT(!stream->local_stream); // Get the ICE ctx NrIceCtx* ctx = static_cast<NrIceCtx*>(obj); + RefPtr<NrIceMediaStream> s = ctx->FindStream(stream); - ctx->SetConnectionState(ICE_CTX_DISCONNECTED); + // We get this callback for destroyed streams in some cases + if (s) { + s->OnGatheringComplete(stream); + } + return 0; +} + +int NrIceCtx::ice_checking(void* obj, nr_ice_peer_ctx* pctx) { + MOZ_MTLOG(ML_DEBUG, "ice_checking called"); + // We don't use this; we react to the stream-specific callbacks instead + return 0; +} + +int NrIceCtx::ice_connected(void* obj, nr_ice_peer_ctx* pctx) { + MOZ_MTLOG(ML_DEBUG, "ice_connected called"); + // We don't use this; we react to the stream-specific callbacks instead + return 0; +} +int NrIceCtx::ice_disconnected(void* obj, nr_ice_peer_ctx* pctx) { + MOZ_MTLOG(ML_DEBUG, "ice_disconnected called"); + // We don't use this; we react to the stream-specific callbacks instead return 0; } @@ -466,7 +521,6 @@ void NrIceCtx::trickle_cb(void* arg, nr_ice_ctx* ice_ctx, } if (!candidate) { - s->SignalCandidate(s, "", stream->ufrag, "", ""); return; } @@ -587,11 +641,20 @@ void NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs) { } bool NrIceCtx::Initialize() { + // Create the gather handler objects + ice_gather_handler_vtbl_ = new nr_ice_gather_handler_vtbl(); + ice_gather_handler_vtbl_->stream_gathering = &NrIceCtx::stream_gathering; + ice_gather_handler_vtbl_->stream_gathered = &NrIceCtx::stream_gathered; + ice_gather_handler_ = new nr_ice_gather_handler(); + ice_gather_handler_->vtbl = ice_gather_handler_vtbl_; + ice_gather_handler_->obj = this; + // Create the ICE context int r; UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION; - r = nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags, &ctx_); + r = nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags, + ice_gather_handler_, &ctx_); if (r) { MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'"); @@ -634,6 +697,16 @@ bool NrIceCtx::Initialize() { ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair; ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready; ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed; + ice_handler_vtbl_->stream_checking = &NrIceCtx::stream_checking; + ice_handler_vtbl_->stream_disconnected = &NrIceCtx::stream_disconnected; + // stream_gathering and stream_gathered do not go here, since those are tied + // to the _local_ nr_ice_media_stream in nICEr. nICEr allows a local + // nr_ice_media_stream (which has a single set of candidates, and therefore a + // single gathering state) to be associated with multiple remote + // nr_ice_media_streams (which each have their own ICE connection state) + // because it allows forking. We never encounter forking, so these will be + // one-to-one in practice, but the architecture in nICEr means we have to set + // up these callbacks on the nr_ice_ctx, not the nr_ice_peer_ctx. ice_handler_vtbl_->ice_connected = &NrIceCtx::ice_connected; ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd; ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking; @@ -720,8 +793,13 @@ NrIceStats NrIceCtx::Destroy() { delete ice_handler_vtbl_; delete ice_handler_; + delete ice_gather_handler_vtbl_; + delete ice_gather_handler_; + ice_handler_vtbl_ = nullptr; ice_handler_ = nullptr; + ice_gather_handler_vtbl_ = nullptr; + ice_gather_handler_ = nullptr; proxy_config_ = nullptr; streams_.clear(); @@ -854,15 +932,10 @@ nsresult NrIceCtx::StartGathering(bool default_route_only, // finished. int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this); - if (!r) { - SetGatheringState(ICE_CTX_GATHER_COMPLETE); - } else if (r == R_WOULDBLOCK) { - SetGatheringState(ICE_CTX_GATHER_STARTED); - } else { - SetGatheringState(ICE_CTX_GATHER_COMPLETE); + if (r && r != R_WOULDBLOCK) { MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't gather ICE candidates for '" << name_ << "', error=" << r); - SetConnectionState(ICE_CTX_FAILED); + SignalAllStreamsFailed(); return NS_ERROR_FAILURE; } @@ -940,7 +1013,7 @@ nsresult NrIceCtx::StartChecks() { r = nr_ice_peer_ctx_pair_candidates(peer_); if (r) { MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't pair candidates on " << name_); - SetConnectionState(ICE_CTX_FAILED); + SignalAllStreamsFailed(); return NS_ERROR_FAILURE; } @@ -952,7 +1025,7 @@ nsresult NrIceCtx::StartChecks() { } else { MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't start peer checks on " << name_); - SetConnectionState(ICE_CTX_FAILED); + SignalAllStreamsFailed(); return NS_ERROR_FAILURE; } } @@ -961,18 +1034,21 @@ nsresult NrIceCtx::StartChecks() { } void NrIceCtx::gather_cb(NR_SOCKET s, int h, void* arg) { - NrIceCtx* ctx = static_cast<NrIceCtx*>(arg); + MOZ_MTLOG(ML_DEBUG, "gather_cb called"); + // We don't use this; we react to the stream-specific callbacks instead +} - ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE); +void NrIceCtx::SignalAllStreamsFailed() { + for (auto& [id, stream] : streams_) { + Unused << id; + stream->Failed(); + SignalConnectionStateChange(stream, ICE_CTX_FAILED); + } } void NrIceCtx::UpdateNetworkState(bool online) { MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): updating network state to " << (online ? "online" : "offline")); - if (connection_state_ == ICE_CTX_CLOSED) { - return; - } - if (online) { nr_ice_peer_ctx_refresh_consent_all_streams(peer_); } else { @@ -980,36 +1056,6 @@ void NrIceCtx::UpdateNetworkState(bool online) { } } -void NrIceCtx::SetConnectionState(ConnectionState state) { - if (state == connection_state_) return; - - MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << connection_state_ - << "->" << state); - connection_state_ = state; - - if (connection_state_ == ICE_CTX_FAILED) { - MOZ_MTLOG(ML_INFO, - "NrIceCtx(" << name_ << "): dumping r_log ringbuffer... "); - std::deque<std::string> logs; - RLogConnector::GetInstance()->GetAny(0, &logs); - for (auto& log : logs) { - MOZ_MTLOG(ML_INFO, log); - } - } - - SignalConnectionStateChange(this, state); -} - -void NrIceCtx::SetGatheringState(GatheringState state) { - if (state == gathering_state_) return; - - MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state " - << gathering_state_ << "->" << state); - gathering_state_ = state; - - SignalGatheringStateChange(this, state); -} - void NrIceCtx::GenerateObfuscatedAddress(nr_ice_candidate* candidate, std::string* mdns_address, std::string* actual_address) { diff --git a/dom/media/webrtc/transport/nricectx.h b/dom/media/webrtc/transport/nricectx.h index a0a0b5b772..01ad6b5dbd 100644 --- a/dom/media/webrtc/transport/nricectx.h +++ b/dom/media/webrtc/transport/nricectx.h @@ -74,6 +74,8 @@ typedef struct nr_ice_peer_ctx_ nr_ice_peer_ctx; typedef struct nr_ice_media_stream_ nr_ice_media_stream; typedef struct nr_ice_handler_ nr_ice_handler; typedef struct nr_ice_handler_vtbl_ nr_ice_handler_vtbl; +typedef struct nr_ice_gather_handler_ nr_ice_gather_handler; +typedef struct nr_ice_gather_handler_vtbl_ nr_ice_gather_handler_vtbl; typedef struct nr_ice_candidate_ nr_ice_candidate; typedef struct nr_ice_cand_pair_ nr_ice_cand_pair; typedef struct nr_ice_stun_server_ nr_ice_stun_server; @@ -200,12 +202,6 @@ class NrIceCtx { ICE_CTX_CLOSED }; - enum GatheringState { - ICE_CTX_GATHER_INIT, - ICE_CTX_GATHER_STARTED, - ICE_CTX_GATHER_COMPLETE - }; - enum Controlling { ICE_CONTROLLING, ICE_CONTROLLED }; enum Policy { ICE_POLICY_RELAY, ICE_POLICY_NO_HOST, ICE_POLICY_ALL }; @@ -294,12 +290,6 @@ class NrIceCtx { // The name of the ctx const std::string& name() const { return name_; } - // Current state - ConnectionState connection_state() const { return connection_state_; } - - // Current state - GatheringState gathering_state() const { return gathering_state_; } - // Get the global attributes std::vector<std::string> GetGlobalAttributes(); @@ -351,9 +341,7 @@ class NrIceCtx { // Signals to indicate events. API users can (and should) // register for these. - sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState> - SignalGatheringStateChange; - sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState> + sigslot::signal2<NrIceMediaStream*, NrIceCtx::ConnectionState> SignalConnectionStateChange; // The thread to direct method calls to @@ -375,7 +363,11 @@ class NrIceCtx { static int select_pair(void* obj, nr_ice_media_stream* stream, int component_id, nr_ice_cand_pair** potentials, int potential_ct); + static int stream_gathering(void* obj, nr_ice_media_stream* stream); + static int stream_gathered(void* obj, nr_ice_media_stream* stream); + static int stream_checking(void* obj, nr_ice_media_stream* stream); static int stream_ready(void* obj, nr_ice_media_stream* stream); + static int stream_disconnected(void* obj, nr_ice_media_stream* stream); static int stream_failed(void* obj, nr_ice_media_stream* stream); static int ice_checking(void* obj, nr_ice_peer_ctx* pctx); static int ice_connected(void* obj, nr_ice_peer_ctx* pctx); @@ -387,28 +379,25 @@ class NrIceCtx { nr_ice_media_stream* stream, int component_id, nr_ice_candidate* candidate); + void SignalAllStreamsFailed(); + // Find a media stream by stream ptr. Gross RefPtr<NrIceMediaStream> FindStream(nr_ice_media_stream* stream); - // Set the state - void SetConnectionState(ConnectionState state); - - // Set the state - void SetGatheringState(GatheringState state); - void GenerateObfuscatedAddress(nr_ice_candidate* candidate, std::string* mdns_address, std::string* actual_address); - ConnectionState connection_state_; - GatheringState gathering_state_; + bool dumped_rlog_ = false; const std::string name_; bool ice_controlling_set_; std::map<std::string, RefPtr<NrIceMediaStream>> streams_; nr_ice_ctx* ctx_; nr_ice_peer_ctx* peer_; - nr_ice_handler_vtbl* ice_handler_vtbl_; // Must be pointer - nr_ice_handler* ice_handler_; // Must be pointer + nr_ice_handler_vtbl* ice_handler_vtbl_; // Must be pointer + nr_ice_handler* ice_handler_; // Must be pointer + nr_ice_gather_handler_vtbl* ice_gather_handler_vtbl_; // Must be pointer + nr_ice_gather_handler* ice_gather_handler_; // Must be pointer bool trickle_; nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on Config config_; diff --git a/dom/media/webrtc/transport/nricemediastream.cpp b/dom/media/webrtc/transport/nricemediastream.cpp index 426aee230e..a3a0c147c9 100644 --- a/dom/media/webrtc/transport/nricemediastream.cpp +++ b/dom/media/webrtc/transport/nricemediastream.cpp @@ -204,11 +204,17 @@ nsresult NrIceMediaStream::ConnectToPeer( MOZ_ASSERT(stream_); if (Matches(old_stream_, ufrag, pwd)) { + bool wasGathering = !AllGenerationsDoneGathering(); // (We swap before we close so we never have stream_ == nullptr) MOZ_MTLOG(ML_DEBUG, "Rolling back to old stream ufrag=" << ufrag << " " << name_); std::swap(stream_, old_stream_); CloseStream(&old_stream_); + if (wasGathering && AllGenerationsDoneGathering()) { + // Special case; we do not need to send another empty candidate, but we + // do need to handle the transition from gathering to complete. + SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_COMPLETE); + } } else if (old_stream_) { // Right now we wait for ICE to complete before closing the old stream. // It might be worth it to close it sooner, but we don't want to close it @@ -273,6 +279,10 @@ nsresult NrIceMediaStream::SetIceCredentials(const std::string& ufrag, } state_ = ICE_CONNECTING; + + MOZ_MTLOG(ML_WARNING, + "SetIceCredentials new=" << stream_ << " old=" << old_stream_); + return NS_OK; } @@ -661,6 +671,21 @@ void NrIceMediaStream::Failed() { } } +void NrIceMediaStream::OnGatheringStarted(nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_WARNING, "OnGatheringStarted called for " << stream); + SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_STARTED); +} + +void NrIceMediaStream::OnGatheringComplete(nr_ice_media_stream* stream) { + MOZ_MTLOG(ML_WARNING, "OnGatheringComplete called for " << stream); + // Spec says to queue two separate tasks; one for the empty candidate, and + // the next for the state change. + SignalCandidate(this, "", stream->ufrag, "", ""); + if (AllGenerationsDoneGathering()) { + SignalGatheringStateChange(GetId(), ICE_STREAM_GATHER_COMPLETE); + } +} + void NrIceMediaStream::Close() { MOZ_MTLOG(ML_DEBUG, "Marking stream closed '" << name_ << "'"); state_ = ICE_CLOSED; @@ -709,4 +734,34 @@ nr_ice_media_stream* NrIceMediaStream::GetStreamForRemoteUfrag( return nullptr; } +bool NrIceMediaStream::AllGenerationsDoneGathering() const { + if (stream_ && !nr_ice_media_stream_is_done_gathering(stream_)) { + return false; + } + if (old_stream_ && !nr_ice_media_stream_is_done_gathering(old_stream_)) { + return false; + } + return true; +} + +bool NrIceMediaStream::AnyGenerationIsConnected() const { + nr_ice_media_stream* peer_stream = nullptr; + + if (stream_ && + !nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream)) { + if (peer_stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED && + !peer_stream->disconnected) { + return true; + } + } + + if (old_stream_ && + !nr_ice_peer_ctx_find_pstream(ctx_->peer(), old_stream_, &peer_stream)) { + if (peer_stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED && + !peer_stream->disconnected) { + return true; + } + } + return false; +} } // namespace mozilla diff --git a/dom/media/webrtc/transport/nricemediastream.h b/dom/media/webrtc/transport/nricemediastream.h index 406373573c..d434dd34dd 100644 --- a/dom/media/webrtc/transport/nricemediastream.h +++ b/dom/media/webrtc/transport/nricemediastream.h @@ -126,6 +126,12 @@ struct NrIceCandidatePair { class NrIceMediaStream { public: + enum GatheringState { + ICE_STREAM_GATHER_INIT, + ICE_STREAM_GATHER_STARTED, + ICE_STREAM_GATHER_COMPLETE + }; + NrIceMediaStream(NrIceCtx* ctx, const std::string& id, const std::string& name, size_t components); @@ -182,6 +188,9 @@ class NrIceMediaStream { void Ready(nr_ice_media_stream* stream); void Failed(); + void OnGatheringStarted(nr_ice_media_stream* stream); + void OnGatheringComplete(nr_ice_media_stream* stream); + // Close the stream. Called by the NrIceCtx. // Different from the destructor because other people // might be holding RefPtrs but we want those writes to fail once @@ -192,9 +201,14 @@ class NrIceMediaStream { // the candidate belongs to. const std::string& GetId() const { return id_; } + bool AllGenerationsDoneGathering() const; + bool AnyGenerationIsConnected() const; + sigslot::signal5<NrIceMediaStream*, const std::string&, const std::string&, const std::string&, const std::string&> SignalCandidate; // A new ICE candidate: + sigslot::signal2<const std::string&, NrIceMediaStream::GatheringState> + SignalGatheringStateChange; sigslot::signal1<NrIceMediaStream*> SignalReady; // Candidate pair ready. sigslot::signal1<NrIceMediaStream*> SignalFailed; // Candidate pair failed. diff --git a/dom/media/webrtc/transport/test/ice_unittest.cpp b/dom/media/webrtc/transport/test/ice_unittest.cpp index 4d097fafa3..50febb3cdd 100644 --- a/dom/media/webrtc/transport/test/ice_unittest.cpp +++ b/dom/media/webrtc/transport/test/ice_unittest.cpp @@ -304,6 +304,8 @@ class SchedulableTrickleCandidate { } void Schedule(unsigned int ms) { + std::cerr << "Scheduling " << Candidate() << " in " << ms << "ms" + << std::endl; test_utils_->SyncDispatchToSTS( WrapRunnable(this, &SchedulableTrickleCandidate::Schedule_s, ms)); } @@ -355,10 +357,7 @@ class IceTestPeer : public sigslot::has_slots<> { offerer_(offerer), stream_counter_(0), shutting_down_(false), - gathering_complete_(false), ready_ct_(0), - ice_connected_(false), - ice_failed_(false), ice_reached_checking_(false), received_(0), sent_(0), @@ -372,8 +371,6 @@ class IceTestPeer : public sigslot::has_slots<> { simulate_ice_lite_(false), nat_(new TestNat), test_utils_(utils) { - ice_ctx_->SignalGatheringStateChange.connect( - this, &IceTestPeer::GatheringStateChange); ice_ctx_->SignalConnectionStateChange.connect( this, &IceTestPeer::ConnectionStateChange); @@ -426,6 +423,10 @@ class IceTestPeer : public sigslot::has_slots<> { stream->SignalReady.connect(this, &IceTestPeer::StreamReady); stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed); stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived); + stream->SignalGatheringStateChange.connect( + this, &IceTestPeer::GatheringStateChange); + mConnectionStates[id] = NrIceCtx::ICE_CTX_INIT; + mGatheringStates[id] = NrIceMediaStream::ICE_STREAM_GATHER_INIT; } void AddStream(int components) { @@ -434,7 +435,10 @@ class IceTestPeer : public sigslot::has_slots<> { } void RemoveStream_s(size_t index) { - ice_ctx_->DestroyStream(MakeTransportId(index)); + const std::string id = MakeTransportId(index); + ice_ctx_->DestroyStream(id); + mConnectionStates.erase(id); + mGatheringStates.erase(id); } void RemoveStream(size_t index) { @@ -650,7 +654,15 @@ class IceTestPeer : public sigslot::has_slots<> { return host_net; } - bool gathering_complete() { return gathering_complete_; } + bool gathering_complete() { + for (const auto& [id, state] : mGatheringStates) { + Unused << id; + if (state != NrIceMediaStream::ICE_STREAM_GATHER_COMPLETE) { + return false; + } + } + return true; + } int ready_ct() { return ready_ct_; } bool is_ready_s(size_t index) { auto media_stream = GetStream_s(index); @@ -666,8 +678,33 @@ class IceTestPeer : public sigslot::has_slots<> { WrapRunnableRet(&result, this, &IceTestPeer::is_ready_s, stream)); return result; } - bool ice_connected() { return ice_connected_; } - bool ice_failed() { return ice_failed_; } + bool ice_connected() { + for (const auto& [id, state] : mConnectionStates) { + if (state != NrIceCtx::ICE_CTX_CONNECTED) { + return false; + } + } + return true; + } + bool ice_failed() { + for (const auto& [id, state] : mConnectionStates) { + if (state == NrIceCtx::ICE_CTX_FAILED) { + return true; + } + } + return false; + } + bool ice_checking() { + if (ice_failed() || ice_connected()) { + return false; + } + for (const auto& [id, state] : mConnectionStates) { + if (state == NrIceCtx::ICE_CTX_CHECKING) { + return true; + } + } + return false; + } bool ice_reached_checking() { return ice_reached_checking_; } size_t received() { return received_; } size_t sent() { return sent_; } @@ -680,13 +717,16 @@ class IceTestPeer : public sigslot::has_slots<> { void RestartIce_s() { for (auto& stream : ice_ctx_->GetStreams()) { SetIceCredentials_s(*stream); + mConnectionStates[stream->GetId()] = NrIceCtx::ICE_CTX_INIT; + mGatheringStates[stream->GetId()] = + NrIceMediaStream::ICE_STREAM_GATHER_INIT; } // take care of some local bookkeeping ready_ct_ = 0; - gathering_complete_ = false; - ice_connected_ = false; - ice_failed_ = false; - ice_reached_checking_ = false; + // We do not unset ice_reached_checking_ here, since we do not expect + // ICE to return to checking in an ICE restart, because the ICE stack + // continues using the old streams (which are probably connected) until the + // new ones are connected. remote_ = nullptr; } @@ -709,9 +749,6 @@ class IceTestPeer : public sigslot::has_slots<> { remote_ = remote; trickle_mode_ = trickle_mode; - ice_connected_ = false; - ice_failed_ = false; - ice_reached_checking_ = false; res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes()); ASSERT_FALSE(remote->simulate_ice_lite_ && (ice_ctx_->GetControlling() == NrIceCtx::ICE_CONTROLLED)); @@ -793,8 +830,11 @@ class IceTestPeer : public sigslot::has_slots<> { auto stream = GetStream_s(index); if (!stream) { // stream might have gone away before the trickle timer popped + std::cerr << "Trickle candidate has no stream: " << index << std::endl; return NS_OK; } + std::cerr << "Trickle candidate for " << index << " (" << stream->GetId() + << "):" << candidate << std::endl; return stream->ParseTrickleCandidate(candidate, ufrag, ""); } @@ -940,16 +980,18 @@ class IceTestPeer : public sigslot::has_slots<> { } // Handle events - void GatheringStateChange(NrIceCtx* ctx, NrIceCtx::GatheringState state) { + void GatheringStateChange(const std::string& aTransportId, + NrIceMediaStream::GatheringState state) { if (shutting_down_) { return; } - if (state != NrIceCtx::ICE_CTX_GATHER_COMPLETE) { + mGatheringStates[aTransportId] = state; + + if (!gathering_complete()) { return; } std::cerr << name_ << " Gathering complete" << std::endl; - gathering_complete_ = true; std::cerr << name_ << " ATTRIBUTES:" << std::endl; for (const auto& stream : ice_ctx_->GetStreams()) { @@ -973,9 +1015,9 @@ class IceTestPeer : public sigslot::has_slots<> { if (candidate.empty()) { return; } - std::cerr << "Candidate for stream " << stream->name() + std::cerr << "Candidate for stream " << stream->GetId() << " initialized: " << candidate << std::endl; - candidates_[stream->name()].push_back(candidate); + candidates_[stream->GetId()].push_back(candidate); // If we are connected, then try to trickle to the other side. if (remote_ && remote_->remote_ && (trickle_mode_ != TRICKLE_SIMULATE)) { @@ -990,7 +1032,7 @@ class IceTestPeer : public sigslot::has_slots<> { return; } } - ADD_FAILURE() << "No matching stream found for " << stream; + ADD_FAILURE() << "No matching stream found for " << stream->GetId(); } } @@ -1133,32 +1175,45 @@ class IceTestPeer : public sigslot::has_slots<> { DumpCandidatePairs_s(stream); } - void ConnectionStateChange(NrIceCtx* ctx, NrIceCtx::ConnectionState state) { - (void)ctx; + void ConnectionStateChange(NrIceMediaStream* stream, + NrIceCtx::ConnectionState state) { + mConnectionStates[stream->GetId()] = state; + if (ice_checking()) { + ice_reached_checking_ = true; + } + switch (state) { case NrIceCtx::ICE_CTX_INIT: break; case NrIceCtx::ICE_CTX_CHECKING: - std::cerr << name_ << " ICE reached checking" << std::endl; - ice_reached_checking_ = true; + std::cerr << name_ << " ICE reached checking (" << stream->GetId() + << ")" << std::endl; + MOZ_ASSERT(ice_reached_checking_); break; case NrIceCtx::ICE_CTX_CONNECTED: - std::cerr << name_ << " ICE connected" << std::endl; - ice_connected_ = true; + std::cerr << name_ << " ICE reached connected (" << stream->GetId() + << ")" << std::endl; + MOZ_ASSERT(ice_reached_checking_); break; case NrIceCtx::ICE_CTX_COMPLETED: - std::cerr << name_ << " ICE completed" << std::endl; + std::cerr << name_ << " ICE reached completed (" << stream->GetId() + << ")" << std::endl; + MOZ_ASSERT(ice_reached_checking_); break; case NrIceCtx::ICE_CTX_FAILED: - std::cerr << name_ << " ICE failed" << std::endl; - ice_failed_ = true; + std::cerr << name_ << " ICE reached failed (" << stream->GetId() << ")" + << std::endl; + MOZ_ASSERT(ice_reached_checking_); break; case NrIceCtx::ICE_CTX_DISCONNECTED: - std::cerr << name_ << " ICE disconnected" << std::endl; - ice_connected_ = false; + std::cerr << name_ << " ICE reached disconnected (" << stream->GetId() + << ")" << std::endl; + MOZ_ASSERT(ice_reached_checking_); + break; + case NrIceCtx::ICE_CTX_CLOSED: + std::cerr << name_ << " ICE reached closed (" << stream->GetId() << ")" + << std::endl; break; - default: - MOZ_CRASH(); } } @@ -1326,10 +1381,9 @@ class IceTestPeer : public sigslot::has_slots<> { std::map<std::string, std::pair<std::string, std::string>> mOldIceCredentials; size_t stream_counter_; bool shutting_down_; - bool gathering_complete_; + std::map<std::string, NrIceCtx::ConnectionState> mConnectionStates; + std::map<std::string, NrIceMediaStream::GatheringState> mGatheringStates; int ready_ct_; - bool ice_connected_; - bool ice_failed_; bool ice_reached_checking_; size_t received_; size_t sent_; @@ -1686,10 +1740,8 @@ class WebRtcIceConnectTest : public StunTest { TrickleMode mode = TRICKLE_NONE) { ASSERT_TRUE(caller->ready_ct() == 0); ASSERT_TRUE(caller->ice_connected() == 0); - ASSERT_TRUE(caller->ice_reached_checking() == 0); ASSERT_TRUE(callee->ready_ct() == 0); ASSERT_TRUE(callee->ice_connected() == 0); - ASSERT_TRUE(callee->ice_reached_checking() == 0); // IceTestPeer::Connect grabs attributes from the first arg, and // gives them to |this|, meaning that callee->Connect(caller, ...) @@ -3361,6 +3413,8 @@ TEST_F(WebRtcIceConnectTest, TestConnectTrickleAddStreamDuringICE) { RealisticTrickleDelay(p1_->ControlTrickle(0)); RealisticTrickleDelay(p2_->ControlTrickle(0)); AddStream(1); + ASSERT_TRUE(Gather()); + ConnectTrickle(); RealisticTrickleDelay(p1_->ControlTrickle(1)); RealisticTrickleDelay(p2_->ControlTrickle(1)); WaitForConnected(1000); diff --git a/dom/media/webrtc/transport/test/test_nr_socket_ice_unittest.cpp b/dom/media/webrtc/transport/test/test_nr_socket_ice_unittest.cpp index b55b05f10c..20754f033b 100644 --- a/dom/media/webrtc/transport/test/test_nr_socket_ice_unittest.cpp +++ b/dom/media/webrtc/transport/test/test_nr_socket_ice_unittest.cpp @@ -73,7 +73,8 @@ class IcePeer { peer_ctx_(nullptr), nat_(nat), test_utils_(test_utils) { - nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags, &ice_ctx_); + nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags, nullptr, + &ice_ctx_); if (nat_) { nr_socket_factory* factory; diff --git a/dom/media/webrtc/transport/test/transport_unittests.cpp b/dom/media/webrtc/transport/test/transport_unittests.cpp index 7729151ade..0e9702ced8 100644 --- a/dom/media/webrtc/transport/test/transport_unittests.cpp +++ b/dom/media/webrtc/transport/test/transport_unittests.cpp @@ -586,16 +586,15 @@ class TransportTestPeer : public sigslot::has_slots<> { void InitIce() { nsresult res; - // Attach our slots - ice_ctx_->SignalGatheringStateChange.connect( - this, &TransportTestPeer::GatheringStateChange); - char name[100]; snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(), (int)streams_.size()); // Create the media stream RefPtr<NrIceMediaStream> stream = ice_ctx_->CreateStream(name, name, 1); + // Attach our slots + stream->SignalGatheringStateChange.connect( + this, &TransportTestPeer::GatheringStateChange); ASSERT_TRUE(stream != nullptr); stream->SetIceCredentials("ufrag", "pass"); @@ -639,9 +638,12 @@ class TransportTestPeer : public sigslot::has_slots<> { << std::endl; } - void GatheringStateChange(NrIceCtx* ctx, NrIceCtx::GatheringState state) { - (void)ctx; - if (state == NrIceCtx::ICE_CTX_GATHER_COMPLETE) { + void GatheringStateChange(const std::string& aTransportId, + NrIceMediaStream::GatheringState state) { + // We only use one stream, no need to check whether all streams are done + // gathering. + Unused << aTransportId; + if (state == NrIceMediaStream::ICE_STREAM_GATHER_COMPLETE) { GatheringComplete(); } } diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.c b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.c index 0d498845a4..b428264e5a 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.c +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.c @@ -325,8 +325,9 @@ int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out) #endif /* USE_TURN */ #define MAXADDRS 100 /* Ridiculously high */ -int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) - { + int nr_ice_ctx_create(char* label, UINT4 flags, + nr_ice_gather_handler* gather_handler, + nr_ice_ctx** ctxp) { nr_ice_ctx *ctx=0; int r,_status; @@ -341,6 +342,8 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) if(!(ctx->label=r_strdup(label))) ABORT(R_NO_MEMORY); + ctx->gather_handler = gather_handler; + /* Get the STUN servers */ if(r=NR_reg_get_child_count(NR_ICE_REG_STUN_SRV_PRFX, (unsigned int *)&ctx->stun_server_ct_cfg)||ctx->stun_server_ct_cfg==0) { @@ -442,7 +445,7 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) int i; nr_ice_stun_id *id1,*id2; - ctx->done_cb = 0; + ctx->gather_done_cb = 0; ctx->trickle_cb = 0; STAILQ_FOREACH_SAFE(s1, &ctx->streams, entry, s2){ @@ -452,6 +455,8 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp) RFREE(ctx->label); + ctx->gather_handler = 0; + RFREE(ctx->stun_servers_cfg); RFREE(ctx->local_addrs); @@ -539,20 +544,26 @@ void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg) } } - if (nr_ice_media_stream_is_done_gathering(stream) && - ctx->trickle_cb) { - ctx->trickle_cb(ctx->trickle_cb_arg, ctx, stream, component_id, NULL); + if (nr_ice_media_stream_is_done_gathering(stream)) { + if (ctx->gather_handler && ctx->gather_handler->vtbl->stream_gathered) { + ctx->gather_handler->vtbl->stream_gathered(ctx->gather_handler->obj, + stream); + } + if (ctx->trickle_cb) { + ctx->trickle_cb(ctx->trickle_cb_arg, ctx, stream, component_id, NULL); + } } if(ctx->uninitialized_candidates==0){ + assert(nr_ice_media_stream_is_done_gathering(stream)); r_log(LOG_ICE, LOG_INFO, "ICE(%s): All candidates initialized", ctx->label); - if (ctx->done_cb) { - ctx->done_cb(0,0,ctx->cb_arg); - } - else { + if (ctx->gather_done_cb) { + ctx->gather_done_cb(0, 0, ctx->cb_arg); + } else { r_log(LOG_ICE, LOG_INFO, - "ICE(%s): No done_cb. We were probably destroyed.", ctx->label); + "ICE(%s): No gather_done_cb. We were probably destroyed.", + ctx->label); } } else { @@ -850,8 +861,7 @@ int nr_ice_set_target_for_default_local_address_lookup(nr_ice_ctx *ctx, const ch return(_status); } -int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg) - { + int nr_ice_gather(nr_ice_ctx* ctx, NR_async_cb gather_done_cb, void* cb_arg) { int r,_status; nr_ice_media_stream *stream; nr_local_addr stun_addrs[MAXADDRS]; @@ -872,7 +882,7 @@ int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg) } r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label); - ctx->done_cb=done_cb; + ctx->gather_done_cb = gather_done_cb; ctx->cb_arg=cb_arg; /* Initialize all the media stream/component pairs */ diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.h b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.h index 8b3081f567..4039c741ec 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.h +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.h @@ -97,9 +97,23 @@ typedef struct nr_ice_stats_ { UINT2 turn_438s; } nr_ice_stats; +typedef struct nr_ice_gather_handler_vtbl_ { + /* This media stream is gathering */ + int (*stream_gathering)(void* obj, nr_ice_media_stream* stream); + + /* This media stream has finished gathering */ + int (*stream_gathered)(void* obj, nr_ice_media_stream* stream); +} nr_ice_gather_handler_vtbl; + +typedef struct nr_ice_gather_handler_ { + void* obj; + nr_ice_gather_handler_vtbl* vtbl; +} nr_ice_gather_handler; + struct nr_ice_ctx_ { UINT4 flags; char *label; + nr_ice_gather_handler* gather_handler; UINT4 Ta; @@ -129,7 +143,7 @@ struct nr_ice_ctx_ { nr_ice_peer_ctx_head peers; nr_ice_stun_id_head ids; - NR_async_cb done_cb; + NR_async_cb gather_done_cb; void *cb_arg; nr_ice_trickle_candidate_cb trickle_cb; @@ -141,7 +155,8 @@ struct nr_ice_ctx_ { nr_transport_addr *target_for_default_local_address_lookup; }; -int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp); +int nr_ice_ctx_create(char* label, UINT4 flags, + nr_ice_gather_handler* gather_handler, nr_ice_ctx** ctxp); int nr_ice_ctx_create_with_credentials(char *label, UINT4 flags, char* ufrag, char* pwd, nr_ice_ctx **ctxp); #define NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION (1) #define NR_ICE_CTX_FLAGS_LITE (1<<1) @@ -156,7 +171,7 @@ void nr_ice_ctx_remove_flags(nr_ice_ctx *ctx, UINT4 flags); void nr_ice_ctx_destroy(nr_ice_ctx** ctxp); int nr_ice_set_local_addresses(nr_ice_ctx *ctx, nr_local_addr* stun_addrs, int stun_addr_ct); int nr_ice_set_target_for_default_local_address_lookup(nr_ice_ctx *ctx, const char *target_ip, UINT2 target_port); -int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg); +int nr_ice_gather(nr_ice_ctx* ctx, NR_async_cb gather_done_cb, void* cb_arg); int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand); void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg); int nr_ice_add_media_stream(nr_ice_ctx *ctx,const char *label,const char *ufrag,const char *pwd,int components, nr_ice_media_stream **streamp); diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_handler.h b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_handler.h index 5a0690adad..ab3e41ef2d 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_handler.h +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_handler.h @@ -56,9 +56,15 @@ int component_id, nr_ice_cand_pair **potentials,int potential_ct); */ int (*stream_ready)(void *obj, nr_ice_media_stream *stream); + /* This media stream is checking */ + int (*stream_checking)(void* obj, nr_ice_media_stream* stream); + /* This media stream has failed */ int (*stream_failed)(void *obj, nr_ice_media_stream *stream); + /* This media stream has disconnected */ + int (*stream_disconnected)(void* obj, nr_ice_media_stream* stream); + /* ICE is connected for this peer ctx */ int (*ice_connected)(void *obj, nr_ice_peer_ctx *pctx); diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.c b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.c index 62bfbad629..90e278bedb 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.c +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.c @@ -80,6 +80,7 @@ int nr_ice_media_stream_create(nr_ice_ctx *ctx,const char *label,const char *ufr stream->component_ct=components; stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED; stream->obsolete = 0; + stream->actually_started_checking = 0; stream->r2l_user = 0; stream->l2r_user = 0; stream->flags = ctx->flags; @@ -177,8 +178,20 @@ int nr_ice_media_stream_initialize(nr_ice_ctx *ctx, nr_ice_media_stream *stream) comp=STAILQ_NEXT(comp,entry); } + if (!nr_ice_media_stream_is_done_gathering(stream) && ctx->gather_handler && + ctx->gather_handler->vtbl->stream_gathering) { + ctx->gather_handler->vtbl->stream_gathering(ctx->gather_handler->obj, + stream); + } + _status=0; abort: + if (_status) { + if (ctx->gather_handler && ctx->gather_handler->vtbl->stream_gathered) { + ctx->gather_handler->vtbl->stream_gathered(ctx->gather_handler->obj, + stream); + } + } return(_status); } @@ -413,6 +426,19 @@ static void nr_ice_media_stream_check_timer_cb(NR_SOCKET s, int h, void *cb_arg) if(pair){ nr_ice_candidate_pair_start(pair->pctx,pair); /* Ignore failures */ + + /* stream->ice_state goes to checking when we decide that it is ok to + * start checking, which can happen before we get remote candidates. We + * want to fire this event when we _actually_ start sending checks. */ + if (!stream->actually_started_checking) { + stream->actually_started_checking = 1; + if (stream->pctx->handler && + stream->pctx->handler->vtbl->stream_checking) { + stream->pctx->handler->vtbl->stream_checking( + stream->pctx->handler->obj, stream->local_stream); + } + } + NR_ASYNC_TIMER_SET(timer_val,nr_ice_media_stream_check_timer_cb,cb_arg,&stream->timer); } else { @@ -729,9 +755,21 @@ void nr_ice_media_stream_set_disconnected(nr_ice_media_stream *stream, int disco if (disconnected == NR_ICE_MEDIA_STREAM_DISCONNECTED) { if (!stream->local_stream->obsolete) { + if (stream->pctx->handler && + stream->pctx->handler->vtbl->stream_disconnected) { + stream->pctx->handler->vtbl->stream_disconnected( + stream->pctx->handler->obj, stream->local_stream); + } nr_ice_peer_ctx_disconnected(stream->pctx); } } else { + if (!stream->local_stream->obsolete) { + if (stream->pctx->handler && + stream->pctx->handler->vtbl->stream_ready) { + stream->pctx->handler->vtbl->stream_ready(stream->pctx->handler->obj, + stream->local_stream); + } + } nr_ice_peer_ctx_check_if_connected(stream->pctx); } } diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.h b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.h index 99f906c100..3da20e3b5e 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.h +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.h @@ -72,6 +72,7 @@ struct nr_ice_media_stream_ { * processing. If this stream is connected already, traffic can continue to * flow for a limited time while the new stream gets ready. */ int obsolete; + int actually_started_checking; #define NR_ICE_MEDIA_STREAM_UNPAIRED 1 #define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2 diff --git a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.c b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.c index 0bf97eb984..bfa1fcf44b 100644 --- a/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.c +++ b/dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.c @@ -671,6 +671,12 @@ void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx) void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx) { + if (pctx->connected_cb_timer) { + /* Whoops, never mind */ + NR_async_timer_cancel(pctx->connected_cb_timer); + pctx->connected_cb_timer = 0; + } + if (pctx->reported_connected && pctx->handler && pctx->handler->vtbl->ice_disconnected) { |