AddRemoteCandidate on the network thread

SdpOfferAnswerHandler now hands over most of the work of adding a
remote candidate over to PeerConnection where the work will be
carried out asynchronously on the network thread (was
synchronous/blocking).

Once added, reporting (ReportRemoteIceCandidateAdded) continues on the
signaling thread as before. The difference is though that we don't
block the UseCandidate() operation which is a part of applying the
local and remote descriptions.

Besides now being asynchronous, there's one behavioural change:
Before starting the 'add' operation, the validity of the candidate
instance to be added, is checked. Previously if such an error occurred,
the error was silently ignored.

Bug: webrtc:9987
Change-Id: Ic1bfb8e27670fc81038b6ccec95ff36c65d12262
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/206063
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33230}
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 15bfefe..0411ab2 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -2521,10 +2521,68 @@
   usage_pattern_.NoteUsageEvent(event);
 }
 
+// Asynchronously adds remote candidates on the network thread.
+void PeerConnection::AddRemoteCandidate(const std::string& mid,
+                                        const cricket::Candidate& candidate) {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+
+  network_thread()->PostTask(ToQueuedTask(
+      network_thread_safety_, [this, mid = mid, candidate = candidate] {
+        RTC_DCHECK_RUN_ON(network_thread());
+        std::vector<cricket::Candidate> candidates = {candidate};
+        RTCError error =
+            transport_controller_->AddRemoteCandidates(mid, candidates);
+        if (error.ok()) {
+          signaling_thread()->PostTask(ToQueuedTask(
+              signaling_thread_safety_.flag(),
+              [this, candidate = std::move(candidate)] {
+                ReportRemoteIceCandidateAdded(candidate);
+                // Candidates successfully submitted for checking.
+                if (ice_connection_state() ==
+                        PeerConnectionInterface::kIceConnectionNew ||
+                    ice_connection_state() ==
+                        PeerConnectionInterface::kIceConnectionDisconnected) {
+                  // If state is New, then the session has just gotten its first
+                  // remote ICE candidates, so go to Checking. If state is
+                  // Disconnected, the session is re-using old candidates or
+                  // receiving additional ones, so go to Checking. If state is
+                  // Connected, stay Connected.
+                  // TODO(bemasc): If state is Connected, and the new candidates
+                  // are for a newly added transport, then the state actually
+                  // _should_ move to checking.  Add a way to distinguish that
+                  // case.
+                  SetIceConnectionState(
+                      PeerConnectionInterface::kIceConnectionChecking);
+                }
+                // TODO(bemasc): If state is Completed, go back to Connected.
+              }));
+        } else {
+          RTC_LOG(LS_WARNING) << error.message();
+        }
+      }));
+}
+
 void PeerConnection::ReportUsagePattern() const {
   usage_pattern_.ReportUsagePattern(observer_);
 }
 
+void PeerConnection::ReportRemoteIceCandidateAdded(
+    const cricket::Candidate& candidate) {
+  RTC_DCHECK_RUN_ON(signaling_thread());
+
+  NoteUsageEvent(UsageEvent::REMOTE_CANDIDATE_ADDED);
+
+  if (candidate.address().IsPrivateIP()) {
+    NoteUsageEvent(UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED);
+  }
+  if (candidate.address().IsUnresolvedIP()) {
+    NoteUsageEvent(UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED);
+  }
+  if (candidate.address().family() == AF_INET6) {
+    NoteUsageEvent(UsageEvent::REMOTE_IPV6_CANDIDATE_ADDED);
+  }
+}
+
 bool PeerConnection::SrtpRequired() const {
   return (dtls_enabled_ ||
           sdp_handler_->webrtc_session_desc_factory()->SdesPolicy() ==