[Unified Plan] SRD: Always set associated remote streams.

This fixes a bug where the streams are not updated if the "msid" changes
without triggering "ontrack", such as if the streams associated with a
receiver changes while the receiver is active.

Bug: webrtc:10083, chromium:916934
Change-Id: Ic7b19ad5ef648ed6880cae4157bf49f8435467ae
Reviewed-on: https://webrtc-review.googlesource.com/c/114161
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26069}
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 642ff49..a70ab2e 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -2532,51 +2532,32 @@
       const MediaContentDescription* media_desc = content->media_description();
       RtpTransceiverDirection local_direction =
           RtpTransceiverDirectionReversed(media_desc->direction());
-      // From the WebRTC specification, steps 2.2.8.5/6 of section 4.4.1.6 "Set
-      // the RTCSessionDescription: If direction is sendrecv or recvonly, and
-      // transceiver's current direction is neither sendrecv nor recvonly,
-      // process the addition of a remote track for the media description.
-      std::vector<std::string> stream_ids;
-      if (!media_desc->streams().empty()) {
-        // The remote description has signaled the stream IDs.
-        stream_ids = media_desc->streams()[0].stream_ids();
-      }
-      if (RtpTransceiverDirectionHasRecv(local_direction) &&
-          (!transceiver->fired_direction() ||
-           !RtpTransceiverDirectionHasRecv(*transceiver->fired_direction()))) {
-        RTC_LOG(LS_INFO) << "Processing the addition of a new track for MID="
-                         << content->name << " (added to "
-                         << GetStreamIdsString(stream_ids) << ").";
-
-        std::vector<rtc::scoped_refptr<MediaStreamInterface>> media_streams;
-        for (const std::string& stream_id : stream_ids) {
-          rtc::scoped_refptr<MediaStreamInterface> stream =
-              remote_streams_->find(stream_id);
-          if (!stream) {
-            stream = MediaStreamProxy::Create(rtc::Thread::Current(),
-                                              MediaStream::Create(stream_id));
-            remote_streams_->AddStream(stream);
-            added_streams.push_back(stream);
-          }
-          media_streams.push_back(stream);
+      // Roughly the same as steps 2.2.8.6 of section 4.4.1.6 "Set the
+      // RTCSessionDescription: Set the associated remote streams given
+      // transceiver.[[Receiver]], msids, addList, and removeList".
+      // https://w3c.github.io/webrtc-pc/#set-the-rtcsessiondescription
+      if (RtpTransceiverDirectionHasRecv(local_direction)) {
+        std::vector<std::string> stream_ids;
+        if (!media_desc->streams().empty()) {
+          // The remote description has signaled the stream IDs.
+          stream_ids = media_desc->streams()[0].stream_ids();
         }
-        // Special case: "a=msid" missing, use random stream ID.
-        if (media_streams.empty() &&
-            !(remote_description()->description()->msid_signaling() &
-              cricket::kMsidSignalingMediaSection)) {
-          if (!missing_msid_default_stream_) {
-            missing_msid_default_stream_ = MediaStreamProxy::Create(
-                rtc::Thread::Current(),
-                MediaStream::Create(rtc::CreateRandomUuid()));
-            added_streams.push_back(missing_msid_default_stream_);
-          }
-          media_streams.push_back(missing_msid_default_stream_);
+        RTC_LOG(LS_INFO) << "Processing the MSIDs for MID=" << content->name
+                         << " (" << GetStreamIdsString(stream_ids) << ").";
+        SetAssociatedRemoteStreams(transceiver->internal()->receiver_internal(),
+                                   stream_ids, &added_streams,
+                                   &removed_streams);
+        // From the WebRTC specification, steps 2.2.8.5/6 of section 4.4.1.6
+        // "Set the RTCSessionDescription: If direction is sendrecv or recvonly,
+        // and transceiver's current direction is neither sendrecv nor recvonly,
+        // process the addition of a remote track for the media description.
+        if (!transceiver->fired_direction() ||
+            !RtpTransceiverDirectionHasRecv(*transceiver->fired_direction())) {
+          RTC_LOG(LS_INFO)
+              << "Processing the addition of a remote track for MID="
+              << content->name << ".";
+          now_receiving_transceivers.push_back(transceiver);
         }
-        // This will add the remote track to the streams.
-        // TODO(hbos): When we remove remote_streams(), use set_stream_ids()
-        // instead. https://crbug.com/webrtc/9480
-        transceiver->internal()->receiver_internal()->SetStreams(media_streams);
-        now_receiving_transceivers.push_back(transceiver);
       }
       // 2.2.8.1.7: If direction is "sendonly" or "inactive", and transceiver's
       // [[FiredDirection]] slot is either "sendrecv" or "recvonly", process the
@@ -2719,6 +2700,46 @@
   return RTCError::OK();
 }
 
+void PeerConnection::SetAssociatedRemoteStreams(
+    rtc::scoped_refptr<RtpReceiverInternal> receiver,
+    const std::vector<std::string>& stream_ids,
+    std::vector<rtc::scoped_refptr<MediaStreamInterface>>* added_streams,
+    std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
+  std::vector<rtc::scoped_refptr<MediaStreamInterface>> media_streams;
+  for (const std::string& stream_id : stream_ids) {
+    rtc::scoped_refptr<MediaStreamInterface> stream =
+        remote_streams_->find(stream_id);
+    if (!stream) {
+      stream = MediaStreamProxy::Create(rtc::Thread::Current(),
+                                        MediaStream::Create(stream_id));
+      remote_streams_->AddStream(stream);
+      added_streams->push_back(stream);
+    }
+    media_streams.push_back(stream);
+  }
+  // Special case: "a=msid" missing, use random stream ID.
+  if (media_streams.empty() &&
+      !(remote_description()->description()->msid_signaling() &
+        cricket::kMsidSignalingMediaSection)) {
+    if (!missing_msid_default_stream_) {
+      missing_msid_default_stream_ = MediaStreamProxy::Create(
+          rtc::Thread::Current(), MediaStream::Create(rtc::CreateRandomUuid()));
+      added_streams->push_back(missing_msid_default_stream_);
+    }
+    media_streams.push_back(missing_msid_default_stream_);
+  }
+  std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
+      receiver->streams();
+  // SetStreams() will add/remove the receiver's track to/from the streams. This
+  // differs from the spec - the spec uses an "addList" and "removeList" to
+  // update the stream-track relationships in a later step. We do this earlier,
+  // changing the order of things, but the end-result is the same.
+  // TODO(hbos): When we remove remote_streams(), use set_stream_ids()
+  // instead. https://crbug.com/webrtc/9480
+  receiver->SetStreams(media_streams);
+  RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
+}
+
 void PeerConnection::ProcessRemovalOfRemoteTrack(
     rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
         transceiver,
@@ -2727,19 +2748,25 @@
   RTC_DCHECK(transceiver->mid());
   RTC_LOG(LS_INFO) << "Processing the removal of a track for MID="
                    << *transceiver->mid();
-  std::vector<rtc::scoped_refptr<MediaStreamInterface>> media_streams =
+  std::vector<rtc::scoped_refptr<MediaStreamInterface>> previous_streams =
       transceiver->internal()->receiver_internal()->streams();
   // This will remove the remote track from the streams.
   transceiver->internal()->receiver_internal()->set_stream_ids({});
   remove_list->push_back(transceiver);
-  // Remove any streams that no longer have tracks.
-  // TODO(https://crbug.com/webrtc/9480): When we use stream IDs instead
-  // of streams, see if the stream was removed by checking if this was the
-  // last receiver with that stream ID.
-  for (auto stream : media_streams) {
-    if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
-      remote_streams_->RemoveStream(stream);
-      removed_streams->push_back(stream);
+  RemoveRemoteStreamsIfEmpty(previous_streams, removed_streams);
+}
+
+void PeerConnection::RemoveRemoteStreamsIfEmpty(
+    const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& remote_streams,
+    std::vector<rtc::scoped_refptr<MediaStreamInterface>>* removed_streams) {
+  // TODO(https://crbug.com/webrtc/9480): When we use stream IDs instead of
+  // streams, see if the stream was removed by checking if this was the last
+  // receiver with that stream ID.
+  for (auto remote_stream : remote_streams) {
+    if (remote_stream->GetAudioTracks().empty() &&
+        remote_stream->GetVideoTracks().empty()) {
+      remote_streams_->RemoveStream(remote_stream);
+      removed_streams->push_back(remote_stream);
     }
   }
 }