From 5e217066fa46cf1a02a3591e4d28de2ae8359420 Mon Sep 17 00:00:00 2001 From: "Byron Campen [:bwc]" Date: Mon, 9 Sep 2013 10:19:01 -0700 Subject: [PATCH] Bug 906990 - Adding a bulk getter for the current state of all ICE candidate pairs(plus a little testing). r=ekr --- media/mtransport/nricemediastream.cpp | 89 ++++++++++++++++--- media/mtransport/nricemediastream.h | 32 +++++++ media/mtransport/test/ice_unittest.cpp | 27 ++++++ .../third_party/nICEr/src/ice/ice_peer_ctx.c | 2 +- .../third_party/nICEr/src/ice/ice_peer_ctx.h | 1 + 5 files changed, 139 insertions(+), 12 deletions(-) diff --git a/media/mtransport/nricemediastream.cpp b/media/mtransport/nricemediastream.cpp index 0f3507f4ce6d..0cd1cb317d9b 100644 --- a/media/mtransport/nricemediastream.cpp +++ b/media/mtransport/nricemediastream.cpp @@ -73,12 +73,9 @@ namespace mozilla { MOZ_MTLOG_MODULE("mtransport") -// Make an NrIceCandidate from the candidate |cand|. -// This is not a member fxn because we want to hide the -// defn of nr_ice_candidate but we pass by reference. -static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) { - ScopedDeletePtr out(new NrIceCandidate()); - +static bool ToNrIceCandidate(const nr_ice_candidate& candc, + NrIceCandidate* out) { + MOZ_ASSERT(out); int r; // Const-cast because the internal nICEr code isn't const-correct. nr_ice_candidate *cand = const_cast(&candc); @@ -86,16 +83,16 @@ static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) { r = nr_transport_addr_get_addrstring(&cand->addr, addr, sizeof(addr)); if (r) - return nullptr; + return false; int port; - r=nr_transport_addr_get_port(&cand->addr, &port); + r = nr_transport_addr_get_port(&cand->addr, &port); if (r) - return nullptr; + return false; NrIceCandidate::Type type; - switch(cand->type) { + switch (cand->type) { case HOST: type = NrIceCandidate::ICE_HOST; break; @@ -109,13 +106,23 @@ static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) { type = NrIceCandidate::ICE_RELAYED; break; default: - return nullptr; + return false; } out->host = addr; out->port = port; out->type = type; + return true; +} +// Make an NrIceCandidate from the candidate |cand|. +// This is not a member fxn because we want to hide the +// defn of nr_ice_candidate but we pass by reference. +static NrIceCandidate* MakeNrIceCandidate(const nr_ice_candidate& candc) { + ScopedDeletePtr out(new NrIceCandidate()); + if (!ToNrIceCandidate(candc, out)) { + return nullptr; + } return out.forget(); } @@ -255,6 +262,66 @@ void NrIceMediaStream::EmitAllCandidates() { RFREE(attrs); } +nsresult NrIceMediaStream::GetCandidatePairs(std::vector* + outPairs) const { + MOZ_ASSERT(outPairs); + + // Get the check_list on the peer stream (this is where the check_list + // actually lives, not in stream_) + nr_ice_media_stream* peerStream = nullptr; + int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peerStream); + if (r != 0) { + return NS_ERROR_FAILURE; + } + + nr_ice_cand_pair *p1; + outPairs->clear(); + + TAILQ_FOREACH(p1, &peerStream->check_list, entry) { + MOZ_ASSERT(p1); + MOZ_ASSERT(p1->local); + MOZ_ASSERT(p1->remote); + NrIceCandidatePair pair; + + switch (p1->state) { + case NR_ICE_PAIR_STATE_FROZEN: + pair.state = NrIceCandidatePair::State::STATE_FROZEN; + break; + case NR_ICE_PAIR_STATE_WAITING: + pair.state = NrIceCandidatePair::State::STATE_WAITING; + break; + case NR_ICE_PAIR_STATE_IN_PROGRESS: + pair.state = NrIceCandidatePair::State::STATE_IN_PROGRESS; + break; + case NR_ICE_PAIR_STATE_FAILED: + pair.state = NrIceCandidatePair::State::STATE_FAILED; + break; + case NR_ICE_PAIR_STATE_SUCCEEDED: + pair.state = NrIceCandidatePair::State::STATE_SUCCEEDED; + break; + case NR_ICE_PAIR_STATE_CANCELLED: + pair.state = NrIceCandidatePair::State::STATE_CANCELLED; + break; + default: + return NS_ERROR_FAILURE; + } + + pair.priority = p1->priority; + pair.nominated = p1->peer_nominated != 0 || p1->nominated != 0; + pair.selected = p1->local->component != nullptr && + p1->local->component->active == p1; + + if (!ToNrIceCandidate(*(p1->local), &pair.local) || + !ToNrIceCandidate(*(p1->remote), &pair.remote)) { + return NS_ERROR_FAILURE; + } + + outPairs->push_back(pair); + } + + return NS_OK; +} + nsresult NrIceMediaStream::GetDefaultCandidate(int component, std::string *addrp, int *portp) { diff --git a/media/mtransport/nricemediastream.h b/media/mtransport/nricemediastream.h index 529ff14797c9..1ac300bca8a4 100644 --- a/media/mtransport/nricemediastream.h +++ b/media/mtransport/nricemediastream.h @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef nricemediastream_h__ #define nricemediastream_h__ +#include #include #include "sigslot.h" @@ -78,6 +79,33 @@ struct NrIceCandidate { Type type; }; +struct NrIceCandidatePair { + + enum State { + STATE_FROZEN, + STATE_WAITING, + STATE_IN_PROGRESS, + STATE_FAILED, + STATE_SUCCEEDED, + STATE_CANCELLED + }; + + State state; + uint64_t priority; + // Set regardless of who nominated it. Does not necessarily mean that it is + // ready to be selected (ie; nominated by peer, but our check has not + // succeeded yet.) Note: since this implementation uses aggressive nomination, + // when we are the controlling agent, this will always be set if the pair is + // in STATE_SUCCEEDED. + bool nominated; + // Set if this candidate pair has been selected. Note: Since we are using + // aggressive nomination, this could change frequently as ICE runs. + bool selected; + NrIceCandidate local; + NrIceCandidate remote; + // TODO(bcampen@mozilla.com): Is it important to put the foundation in here? +}; + class NrIceMediaStream { public: static RefPtr Create(NrIceCtx *ctx, @@ -95,6 +123,10 @@ class NrIceMediaStream { // Get all the candidates std::vector GetCandidates() const; + // Get all candidate pairs, whether in the check list or triggered check + // queue, in priority order. outPairs is cleared before being filled. + nsresult GetCandidatePairs(std::vector* outPairs) const; + // Get the default candidate as host and port nsresult GetDefaultCandidate(int component, std::string *host, int *port); diff --git a/media/mtransport/test/ice_unittest.cpp b/media/mtransport/test/ice_unittest.cpp index ec5c976767d0..2db140103f7f 100644 --- a/media/mtransport/test/ice_unittest.cpp +++ b/media/mtransport/test/ice_unittest.cpp @@ -107,6 +107,7 @@ class IceTestPeer : public sigslot::has_slots<> { streams_.push_back(stream); stream->SignalCandidate.connect(this, &IceTestPeer::GotCandidate); stream->SignalReady.connect(this, &IceTestPeer::StreamReady); + stream->SignalFailed.connect(this, &IceTestPeer::StreamFailed); stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived); } @@ -353,9 +354,35 @@ class IceTestPeer : public sigslot::has_slots<> { candidates_[stream->name()].push_back(candidate); } + void DumpCandidatePairs(NrIceMediaStream *stream) { + std::vector pairs; + nsresult r = stream->GetCandidatePairs(&pairs); + ASSERT_TRUE(NS_SUCCEEDED(r)); + + std::cerr << "Begin list of candidate pairs [" << std::endl; + + for (std::vector::iterator p = pairs.begin(); + p != pairs.end(); ++p) { + std::cerr << std::endl; + DumpCandidate("Local", p->local); + DumpCandidate("Remote", p->remote); + std::cerr << "state = " << p->state + << " priority = " << p->priority + << " nominated = " << p->nominated + << " selected = " << p->selected << std::endl; + } + std::cerr << "]" << std::endl; + } + void StreamReady(NrIceMediaStream *stream) { ++ready_ct_; std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl; + DumpCandidatePairs(stream); + } + + void StreamFailed(NrIceMediaStream *stream) { + std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl; + DumpCandidatePairs(stream); } void IceCompleted(NrIceCtx *ctx) { diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c index 6a9d4f2dcb76..bab16d4537a0 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c +++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.c @@ -229,7 +229,7 @@ static int nr_ice_ctx_parse_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream return(_status); } -static int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp) +int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp) { int _status; nr_ice_media_stream *pstream; diff --git a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h index c6fd1e4b53bb..494f84be75c0 100644 --- a/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h +++ b/media/mtransport/third_party/nICEr/src/ice/ice_peer_ctx.h @@ -67,6 +67,7 @@ typedef STAILQ_HEAD(nr_ice_peer_ctx_head_, nr_ice_peer_ctx_) nr_ice_peer_ctx_hea int nr_ice_peer_ctx_create(nr_ice_ctx *ctx, nr_ice_handler *handler,char *label, nr_ice_peer_ctx **pctxp); int nr_ice_peer_ctx_destroy(nr_ice_peer_ctx **pctxp); int nr_ice_peer_ctx_parse_stream_attributes(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char **attrs, int attr_ct); +int nr_ice_peer_ctx_find_pstream(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, nr_ice_media_stream **pstreamp); int nr_ice_peer_ctx_parse_trickle_candidate(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *cand); int nr_ice_peer_ctx_pair_candidates(nr_ice_peer_ctx *pctx);