summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/transport
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:33 +0000
commit086c044dc34dfc0f74fbe41f4ecb402b2cd34884 (patch)
treea4f824bd33cb075dd5aa3eb5a0a94af221bbe83a /dom/media/webrtc/transport
parentAdding debian version 124.0.1-1. (diff)
downloadfirefox-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')
-rw-r--r--dom/media/webrtc/transport/nricectx.cpp180
-rw-r--r--dom/media/webrtc/transport/nricectx.h39
-rw-r--r--dom/media/webrtc/transport/nricemediastream.cpp55
-rw-r--r--dom/media/webrtc/transport/nricemediastream.h14
-rw-r--r--dom/media/webrtc/transport/test/ice_unittest.cpp134
-rw-r--r--dom/media/webrtc/transport/test/test_nr_socket_ice_unittest.cpp3
-rw-r--r--dom/media/webrtc/transport/test/transport_unittests.cpp16
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.c38
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_ctx.h21
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_handler.h6
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.c38
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_media_stream.h1
-rw-r--r--dom/media/webrtc/transport/third_party/nICEr/src/ice/ice_peer_ctx.c6
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) {