Bug 906990: Part 13. Get local/remote candidates separately, instead of grabbing them from candidate pairs (means we can get candidates before pairing happens). r=ekr
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 13 Nov 2013 13:49:33 -0800
changeset 163612 61da9e9b3c28045f06bcdffc8c34aafc96e3f375
parent 163611 26bd374d35135aee46c08ae0d9a0a20fa6a06e26
child 163613 07a8653c8ba66ffe64b0ed649d29991fb9249774
push id4362
push userryanvm@gmail.com
push dateWed, 15 Jan 2014 19:37:00 +0000
treeherderfx-team@d9b7e256c5d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersekr
bugs906990
milestone29.0a1
Bug 906990: Part 13. Get local/remote candidates separately, instead of grabbing them from candidate pairs (means we can get candidates before pairing happens). r=ekr
media/mtransport/nricemediastream.cpp
media/mtransport/nricemediastream.h
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
--- a/media/mtransport/nricemediastream.cpp
+++ b/media/mtransport/nricemediastream.cpp
@@ -399,16 +399,59 @@ std::vector<std::string> NrIceMediaStrea
     RFREE(attrs[i]);
   }
 
   RFREE(attrs);
 
   return ret;
 }
 
+static nsresult GetCandidatesFromStream(
+    nr_ice_media_stream *stream,
+    std::vector<NrIceCandidate> *candidates) {
+  MOZ_ASSERT(candidates);
+  nr_ice_component* comp=STAILQ_FIRST(&stream->components);
+  while(comp){
+    if (comp->state != NR_ICE_COMPONENT_DISABLED) {
+      nr_ice_candidate *cand = TAILQ_FIRST(&comp->candidates);
+      while(cand){
+        NrIceCandidate new_cand;
+        // This can fail if the candidate is server reflexive or relayed, and
+        // has not yet received a response (ie; it doesn't know its address
+        // yet). For the purposes of this code, this isn't a candidate we're
+        // interested in, since it is not fully baked yet.
+        if (ToNrIceCandidate(*cand, &new_cand)) {
+          candidates->push_back(new_cand);
+        }
+        cand=TAILQ_NEXT(cand,entry_comp);
+      }
+    }
+    comp=STAILQ_NEXT(comp,entry);
+  }
+
+  return NS_OK;
+}
+
+nsresult NrIceMediaStream::GetLocalCandidates(
+    std::vector<NrIceCandidate>* candidates) const {
+  return GetCandidatesFromStream(stream_, candidates);
+}
+
+nsresult NrIceMediaStream::GetRemoteCandidates(
+    std::vector<NrIceCandidate>* candidates) const {
+  nr_ice_media_stream* peer_stream;
+  int r = nr_ice_peer_ctx_find_pstream(ctx_->peer(), stream_, &peer_stream);
+  if (r != 0) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return GetCandidatesFromStream(peer_stream, candidates);
+}
+
+
 nsresult NrIceMediaStream::DisableComponent(int component_id) {
   if (!stream_)
     return NS_ERROR_FAILURE;
 
   int r = nr_ice_media_stream_disable_component(stream_,
                                                 component_id);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't disable '" << name_ << "':" <<
--- a/media/mtransport/nricemediastream.h
+++ b/media/mtransport/nricemediastream.h
@@ -132,16 +132,19 @@ class NrIceMediaStream {
   State state() const { return state_; }
 
   // The name of the stream
   const std::string& name() const { return name_; }
 
   // Get all the candidates
   std::vector<std::string> GetCandidates() const;
 
+  nsresult GetLocalCandidates(std::vector<NrIceCandidate>* candidates) const;
+  nsresult GetRemoteCandidates(std::vector<NrIceCandidate>* candidates) const;
+
   // Get all candidate pairs, whether in the check list or triggered check
   // queue, in priority order. |out_pairs| is cleared before being filled.
   nsresult GetCandidatePairs(std::vector<NrIceCandidatePair>* out_pairs) const;
 
   // Get the default candidate as host and port
   nsresult GetDefaultCandidate(int component, std::string *host, int *port);
 
   // Parse remote attributes
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1287,17 +1287,20 @@ PushBackSelect(std::vector<RefPtr<MediaP
 }
 #endif
 
 NS_IMETHODIMP
 PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector, bool internalStats) {
   PC_AUTO_ENTER_API_CALL(true);
 
 #ifdef MOZILLA_INTERNAL_API
-  MOZ_ASSERT(mMedia);
+  if (!mMedia) {
+    // Since we zero this out before the d'tor, we should check.
+    return NS_ERROR_UNEXPECTED;
+  }
 
   // Gather up pipelines from mMedia and dispatch them to STS for inspection
 
   std::vector<RefPtr<MediaPipeline>> pipelines;
   TrackID trackId = aSelector ? aSelector->GetTrackID() : 0;
 
   for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
     PushBackSelect(pipelines, mMedia->GetLocalStream(i)->GetPipelines(), trackId);
@@ -1947,25 +1950,28 @@ PeerConnectionImpl::IceGatheringStateCha
                              &PeerConnectionObserver::OnStateChange,
                              PCObserverStateType::IceGatheringState,
                              rv, static_cast<JSCompartment*>(nullptr)),
                 NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 #ifdef MOZILLA_INTERNAL_API
+
 nsresult
 PeerConnectionImpl::GetStatsImpl_s(
     bool internalStats,
     const std::vector<RefPtr<MediaPipeline>>& pipelines,
     const RefPtr<NrIceCtx>& iceCtx,
     const std::vector<RefPtr<NrIceMediaStream>>& streams,
     DOMHighResTimeStamp now,
     RTCStatsReportInternal* report) {
 
+  ASSERT_ON_THREAD(iceCtx->thread());
+
   // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
 
   for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
     const MediaPipeline& mp = **it;
     nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ?
         NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
     idstr.AppendInt(mp.trackid());
 
@@ -2000,93 +2006,108 @@ PeerConnectionImpl::GetStatsImpl_s(
   // Gather stats from ICE
   for (auto s = streams.begin(); s != streams.end(); ++s) {
     FillStatsReport_s(**s, internalStats, now, report);
   }
 
   return NS_OK;
 }
 
+static void ToRTCIceCandidateStats(
+    const std::vector<NrIceCandidate>& candidates,
+    RTCStatsType candidateType,
+    const nsString& componentId,
+    DOMHighResTimeStamp now,
+    RTCStatsReportInternal* report) {
+
+  MOZ_ASSERT(report);
+  for (auto c = candidates.begin(); c != candidates.end(); ++c) {
+    RTCIceCandidateStats cand;
+    cand.mType.Construct(candidateType);
+    NS_ConvertASCIItoUTF16 codeword(c->codeword.c_str());
+    cand.mComponentId.Construct(componentId);
+    cand.mId.Construct(codeword);
+    cand.mTimestamp.Construct(now);
+    cand.mCandidateType.Construct(
+        RTCStatsIceCandidateType(c->type));
+    cand.mIpAddress.Construct(
+        NS_ConvertASCIItoUTF16(c->cand_addr.host.c_str()));
+    cand.mPortNumber.Construct(c->cand_addr.port);
+    report->mIceCandidateStats.Value().AppendElement(cand);
+  }
+}
+
 void PeerConnectionImpl::FillStatsReport_s(
     NrIceMediaStream& mediaStream,
     bool internalStats,
     DOMHighResTimeStamp now,
     RTCStatsReportInternal* report) {
-  std::vector<NrIceCandidatePair> candPairs;
-  nsresult res = mediaStream.GetCandidatePairs(&candPairs);
-
-  if (NS_FAILED(res)) {
-    CSFLogError(logTag, "%s: Error getting candidate pairs", __FUNCTION__);
-    return;
-  }
 
   NS_ConvertASCIItoUTF16 componentId(mediaStream.name().c_str());
-  for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
-    NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
-    NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
-    NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
-    // Only expose candidate-pair statistics to chrome, until we've thought
-    // through the implications of exposing it to content.
+  if (internalStats) {
+    std::vector<NrIceCandidatePair> candPairs;
+    nsresult res = mediaStream.GetCandidatePairs(&candPairs);
+    if (NS_FAILED(res)) {
+      CSFLogError(logTag, "%s: Error getting candidate pairs", __FUNCTION__);
+      return;
+    }
 
-    if (internalStats) {
+    for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
+      NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
+      NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
+      NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
+      // Only expose candidate-pair statistics to chrome, until we've thought
+      // through the implications of exposing it to content.
+
       RTCIceCandidatePairStats s;
       s.mId.Construct(codeword);
       s.mComponentId.Construct(componentId);
       s.mTimestamp.Construct(now);
       s.mType.Construct(RTCStatsType::Candidatepair);
-
       s.mLocalCandidateId.Construct(localCodeword);
       s.mRemoteCandidateId.Construct(remoteCodeword);
       s.mNominated.Construct(p->nominated);
       s.mMozPriority.Construct(p->priority);
       s.mSelected.Construct(p->selected);
       s.mState.Construct(RTCStatsIceCandidatePairState(p->state));
       report->mIceCandidatePairStats.Value().AppendElement(s);
     }
+  }
 
-    {
-      RTCIceCandidateStats local;
-      local.mComponentId.Construct(componentId);
-      local.mId.Construct(localCodeword);
-      local.mTimestamp.Construct(now);
-      local.mType.Construct(RTCStatsType::Localcandidate);
-      local.mCandidateType.Construct(
-          RTCStatsIceCandidateType(p->local.type));
-      local.mIpAddress.Construct(
-          NS_ConvertASCIItoUTF16(p->local.cand_addr.host.c_str()));
-      local.mPortNumber.Construct(p->local.cand_addr.port);
-      report->mIceCandidateStats.Value().AppendElement(local);
-    }
+  std::vector<NrIceCandidate> candidates;
+  if (NS_SUCCEEDED(mediaStream.GetLocalCandidates(&candidates))) {
+    ToRTCIceCandidateStats(candidates,
+                           RTCStatsType::Localcandidate,
+                           componentId,
+                           now,
+                           report);
+  }
+  candidates.clear();
 
-    {
-      RTCIceCandidateStats remote;
-      remote.mComponentId.Construct(componentId);
-      remote.mId.Construct(remoteCodeword);
-      remote.mTimestamp.Construct(now);
-      remote.mType.Construct(RTCStatsType::Remotecandidate);
-      remote.mCandidateType.Construct(
-          RTCStatsIceCandidateType(p->remote.type));
-      remote.mIpAddress.Construct(
-          NS_ConvertASCIItoUTF16(p->remote.cand_addr.host.c_str()));
-      remote.mPortNumber.Construct(p->remote.cand_addr.port);
-      report->mIceCandidateStats.Value().AppendElement(remote);
-    }
+  if (NS_SUCCEEDED(mediaStream.GetRemoteCandidates(&candidates))) {
+    ToRTCIceCandidateStats(candidates,
+                           RTCStatsType::Remotecandidate,
+                           componentId,
+                           now,
+                           report);
   }
 }
 
 void PeerConnectionImpl::GetStats_s(
     const std::string& pcHandle, // The Runnable holds the memory
     const std::string& pcName, // The Runnable holds the memory
     nsCOMPtr<nsIThread> callbackThread,
     bool internalStats,
     const std::vector<RefPtr<MediaPipeline>>& pipelines,
     const RefPtr<NrIceCtx>& iceCtx,
     const std::vector<RefPtr<NrIceMediaStream>>& streams,
     DOMHighResTimeStamp now) {
 
+  ASSERT_ON_THREAD(iceCtx->thread());
+
   // We do not use the pcHandle here, since that's risky to expose to content.
   nsAutoPtr<RTCStatsReportInternal> report(
       new RTCStatsReportInternalConstruct(
           NS_ConvertASCIItoUTF16(pcName.c_str()),
           now));
 
   nsresult rv = GetStatsImpl_s(internalStats,
                                pipelines,