Refactor UpdatePayloadTypeDemuxingState and add documentation.

This simplifies the work that happens on the worker thread in
preparation of avoiding having to go to the worker at all.

Bug: webrtc:11993
Change-Id: I13f063bdecce8efdb978ef1976c819019f30e020
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/244082
Auto-Submit: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35610}
diff --git a/pc/channel.cc b/pc/channel.cc
index 7b6c0c8..7c386c8 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -302,6 +302,12 @@
 }
 
 bool BaseChannel::SetPayloadTypeDemuxingEnabled(bool enabled) {
+  // TODO(bugs.webrtc.org/11993): The demuxer state needs to be managed on the
+  // network thread. At the moment there's a workaround for inconsistent state
+  // between the worker and network thread because of this (see
+  // OnDemuxerCriteriaUpdatePending elsewhere in this file) and
+  // SetPayloadTypeDemuxingEnabled_w has an Invoke over to the network thread
+  // to apply state updates.
   RTC_DCHECK_RUN_ON(worker_thread());
   TRACE_EVENT0("webrtc", "BaseChannel::SetPayloadTypeDemuxingEnabled");
   return SetPayloadTypeDemuxingEnabled_w(enabled);
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index 4332cd6..235d508 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -4947,29 +4947,6 @@
     }
   }
 
-  // Gather all updates ahead of time so that all channels can be updated in a
-  // single Invoke; necessary due to thread guards.
-  std::vector<std::pair<RtpTransceiverDirection, cricket::ChannelInterface*>>
-      channels_to_update;
-  for (const auto& transceiver : transceivers()->ListInternal()) {
-    cricket::ChannelInterface* channel = transceiver->channel();
-    const ContentInfo* content =
-        FindMediaSectionForTransceiver(transceiver, sdesc);
-    if (!channel || !content) {
-      continue;
-    }
-    RtpTransceiverDirection local_direction =
-        content->media_description()->direction();
-    if (source == cricket::CS_REMOTE) {
-      local_direction = RtpTransceiverDirectionReversed(local_direction);
-    }
-    channels_to_update.emplace_back(local_direction, transceiver->channel());
-  }
-
-  if (channels_to_update.empty()) {
-    return true;
-  }
-
   // In Unified Plan, payload type demuxing is useful for legacy endpoints that
   // don't support the MID header extension, but it can also cause incorrrect
   // forwarding of packets when going from one m= section to multiple m=
@@ -4996,44 +4973,71 @@
     bundled_pt_demux_allowed_video = true;
   }
 
+  // Gather all updates ahead of time so that all channels can be updated in a
+  // single Invoke; necessary due to thread guards.
+  std::vector<std::pair<bool, cricket::ChannelInterface*>> channels_to_update;
+  for (const auto& transceiver : transceivers()->ListInternal()) {
+    cricket::ChannelInterface* channel = transceiver->channel();
+    const ContentInfo* content =
+        FindMediaSectionForTransceiver(transceiver, sdesc);
+    if (!channel || !content) {
+      continue;
+    }
+
+    const cricket::MediaType media_type = channel->media_type();
+    if (media_type != cricket::MediaType::MEDIA_TYPE_AUDIO &&
+        media_type != cricket::MediaType::MEDIA_TYPE_VIDEO) {
+      continue;
+    }
+
+    RtpTransceiverDirection local_direction =
+        content->media_description()->direction();
+    if (source == cricket::CS_REMOTE) {
+      local_direction = RtpTransceiverDirectionReversed(local_direction);
+    }
+
+    auto bundle_it = bundle_groups_by_mid.find(channel->content_name());
+    const cricket::ContentGroup* bundle_group =
+        bundle_it != bundle_groups_by_mid.end() ? bundle_it->second : nullptr;
+    bool pt_demux_enabled = RtpTransceiverDirectionHasRecv(local_direction);
+    if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) {
+      pt_demux_enabled &=
+          !bundle_group ||
+          (bundled_pt_demux_allowed_audio &&
+           payload_types_by_bundle[bundle_group].pt_demuxing_possible_audio);
+      if (pt_demux_enabled) {
+        pt_demuxing_has_been_used_audio_ = true;
+      }
+    } else {
+      RTC_DCHECK_EQ(media_type, cricket::MediaType::MEDIA_TYPE_VIDEO);
+      pt_demux_enabled &=
+          !bundle_group ||
+          (bundled_pt_demux_allowed_video &&
+           payload_types_by_bundle[bundle_group].pt_demuxing_possible_video);
+      if (pt_demux_enabled) {
+        pt_demuxing_has_been_used_video_ = true;
+      }
+    }
+
+    channels_to_update.emplace_back(pt_demux_enabled, transceiver->channel());
+  }
+
+  if (channels_to_update.empty()) {
+    return true;
+  }
+
+  // TODO(bugs.webrtc.org/11993): This Invoke() will also invoke on the network
+  // thread for every demuxer sink that needs to be updated. The demuxer state
+  // needs to be fully (and only) managed on the network thread and once that's
+  // the case, there's no need to stop by on the worker. Ideally we could also
+  // do this without blocking.
   return pc_->worker_thread()->Invoke<bool>(
-      RTC_FROM_HERE,
-      [&channels_to_update, &bundle_groups_by_mid, &payload_types_by_bundle,
-       bundled_pt_demux_allowed_audio, bundled_pt_demux_allowed_video,
-       pt_demuxing_has_been_used_audio = &pt_demuxing_has_been_used_audio_,
-       pt_demuxing_has_been_used_video = &pt_demuxing_has_been_used_video_]() {
+      RTC_FROM_HERE, [&channels_to_update]() {
         for (const auto& it : channels_to_update) {
-          RtpTransceiverDirection local_direction = it.first;
-          cricket::ChannelInterface* channel = it.second;
-          cricket::MediaType media_type = channel->media_type();
-          auto bundle_it = bundle_groups_by_mid.find(channel->content_name());
-          const cricket::ContentGroup* bundle_group =
-              bundle_it != bundle_groups_by_mid.end() ? bundle_it->second
-                                                      : nullptr;
-          if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) {
-            bool pt_demux_enabled =
-                RtpTransceiverDirectionHasRecv(local_direction) &&
-                (!bundle_group || (bundled_pt_demux_allowed_audio &&
-                                   payload_types_by_bundle[bundle_group]
-                                       .pt_demuxing_possible_audio));
-            if (pt_demux_enabled) {
-              *pt_demuxing_has_been_used_audio = true;
-            }
-            if (!channel->SetPayloadTypeDemuxingEnabled(pt_demux_enabled)) {
-              return false;
-            }
-          } else if (media_type == cricket::MediaType::MEDIA_TYPE_VIDEO) {
-            bool pt_demux_enabled =
-                RtpTransceiverDirectionHasRecv(local_direction) &&
-                (!bundle_group || (bundled_pt_demux_allowed_video &&
-                                   payload_types_by_bundle[bundle_group]
-                                       .pt_demuxing_possible_video));
-            if (pt_demux_enabled) {
-              *pt_demuxing_has_been_used_video = true;
-            }
-            if (!channel->SetPayloadTypeDemuxingEnabled(pt_demux_enabled)) {
-              return false;
-            }
+          if (!it.second->SetPayloadTypeDemuxingEnabled(it.first)) {
+            // Note that the state has already been irrevocably changed at this
+            // point. Is it useful to stop the loop?
+            return false;
           }
         }
         return true;