Add IsEmpty to RtpStreamReceiverController and RtpDemuxer

Additionally make ResolveSink public and expose it via the
RtpStreamReceiverController class. This allows decoupling the demuxing
operations from the receiving sinks in a follow-up set of changes as
operations are moved from the worker thread to the network thread.

Bug: webrtc:42222117
Change-Id: I68716390cf655e7134b75667e39f678285c83760
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/471120
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#47680}
diff --git a/call/call.cc b/call/call.cc
index 2cae632..6110758 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -749,6 +749,8 @@
   RTC_CHECK(video_send_streams_.empty());
   RTC_CHECK(audio_receive_streams_.empty());
   RTC_CHECK(video_receive_streams_.empty());
+  RTC_CHECK(audio_receiver_controller_.IsEmpty());
+  RTC_CHECK(video_receiver_controller_.IsEmpty());
 
   receive_side_cc_periodic_task_.Stop();
   elastic_bandwidth_allocation_task_.Stop();
diff --git a/call/rtp_demuxer.cc b/call/rtp_demuxer.cc
index e078347..6821fe0 100644
--- a/call/rtp_demuxer.cc
+++ b/call/rtp_demuxer.cc
@@ -125,6 +125,12 @@
   RTC_DCHECK(sink_by_rsid_.empty());
 }
 
+bool RtpDemuxer::IsEmpty() const {
+  return sink_by_mid_.empty() && sink_by_ssrc_.empty() &&
+         sinks_by_pt_.empty() && sink_by_mid_and_rsid_.empty() &&
+         sink_by_rsid_.empty() && match_any_sink_ == nullptr;
+}
+
 bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria,
                          RtpPacketSinkInterface* sink) {
   RTC_DCHECK(criteria.match_any() || !criteria.payload_types().empty() ||
@@ -193,9 +199,7 @@
   if (criteria.match_any()) {
     // A match_all criteria conflicts if and only if we have another sink
     // already registered.
-    return (!sink_by_mid_.empty() || !sink_by_ssrc_.empty() ||
-            !sinks_by_pt_.empty() || !sink_by_mid_and_rsid_.empty() ||
-            !sink_by_rsid_.empty());
+    return !IsEmpty();
   }
 
   if (!criteria.mid().empty()) {
diff --git a/call/rtp_demuxer.h b/call/rtp_demuxer.h
index f2f76cb..24d50de 100644
--- a/call/rtp_demuxer.h
+++ b/call/rtp_demuxer.h
@@ -140,6 +140,8 @@
     use_payload_type_demuxing_ = enable;
   }
 
+  bool IsEmpty() const;
+
   // Registers a sink that will be notified when RTP packets match its given
   // criteria according to the algorithm described in the class description.
   // Returns true if the sink was successfully added.
@@ -171,6 +173,12 @@
   // Returns the set of SSRCs associated with a sink.
   flat_set<uint32_t> GetSsrcsForSink(const RtpPacketSinkInterface* sink) const;
 
+  // Runs the demux algorithm on the given packet and returns the sink that
+  // should receive the packet.
+  // Will record any SSRC<->ID associations along the way.
+  // If the packet should be dropped, this method returns null.
+  RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet);
+
   // Demuxes the given packet and forwards it to the chosen sink. Returns true
   // if the packet was forwarded and false if the packet was dropped.
   bool OnRtpPacket(const RtpPacketReceived& packet);
@@ -180,12 +188,6 @@
   // with the existing criteria and should be rejected.
   bool CriteriaWouldConflict(const RtpDemuxerCriteria& criteria) const;
 
-  // Runs the demux algorithm on the given packet and returns the sink that
-  // should receive the packet.
-  // Will record any SSRC<->ID associations along the way.
-  // If the packet should be dropped, this method returns null.
-  RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet);
-
   // Used by the ResolveSink algorithm.
   RtpPacketSinkInterface* ResolveSinkByMid(absl::string_view mid,
                                            uint32_t ssrc);
diff --git a/call/rtp_demuxer_unittest.cc b/call/rtp_demuxer_unittest.cc
index b878d2b..c358b5e 100644
--- a/call/rtp_demuxer_unittest.cc
+++ b/call/rtp_demuxer_unittest.cc
@@ -1349,6 +1349,30 @@
   EXPECT_FALSE(demuxer_.OnRtpPacket(*packet));
 }
 
+TEST_F(RtpDemuxerTest, IsEmptyMatchesSinksPresence) {
+  EXPECT_TRUE(demuxer_.IsEmpty());
+
+  MockRtpPacketSink sink;
+  constexpr uint32_t ssrc = 101;
+  EXPECT_TRUE(AddSinkOnlySsrc(ssrc, &sink));
+  EXPECT_FALSE(demuxer_.IsEmpty());
+
+  EXPECT_TRUE(RemoveSink(&sink));
+  EXPECT_TRUE(demuxer_.IsEmpty());
+}
+
+TEST_F(RtpDemuxerTest, ResolveSinkReturnsCorrectSink) {
+  constexpr uint32_t ssrc = 101;
+  MockRtpPacketSink sink;
+  EXPECT_TRUE(AddSinkOnlySsrc(ssrc, &sink));
+
+  auto packet = CreatePacketWithSsrc(ssrc);
+  EXPECT_EQ(demuxer_.ResolveSink(*packet), &sink);
+
+  auto unknown_packet = CreatePacketWithSsrc(ssrc + 1);
+  EXPECT_EQ(demuxer_.ResolveSink(*unknown_packet), nullptr);
+}
+
 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
 
 TEST_F(RtpDemuxerDeathTest, MidMustNotExceedMaximumLength) {
diff --git a/call/rtp_stream_receiver_controller.cc b/call/rtp_stream_receiver_controller.cc
index 9367b87..68b979d 100644
--- a/call/rtp_stream_receiver_controller.cc
+++ b/call/rtp_stream_receiver_controller.cc
@@ -49,6 +49,17 @@
   return std::make_unique<Receiver>(this, ssrc, sink);
 }
 
+bool RtpStreamReceiverController::IsEmpty() const {
+  RTC_DCHECK_RUN_ON(&demuxer_sequence_);
+  return demuxer_.IsEmpty();
+}
+
+RtpPacketSinkInterface* RtpStreamReceiverController::ResolveSink(
+    const RtpPacketReceived& packet) {
+  RTC_DCHECK_RUN_ON(&demuxer_sequence_);
+  return demuxer_.ResolveSink(packet);
+}
+
 bool RtpStreamReceiverController::OnRtpPacket(const RtpPacketReceived& packet) {
   RTC_DCHECK_RUN_ON(&demuxer_sequence_);
   return demuxer_.OnRtpPacket(packet);
diff --git a/call/rtp_stream_receiver_controller.h b/call/rtp_stream_receiver_controller.h
index 1954c4f..a10d774 100644
--- a/call/rtp_stream_receiver_controller.h
+++ b/call/rtp_stream_receiver_controller.h
@@ -38,6 +38,8 @@
       uint32_t ssrc,
       RtpPacketSinkInterface* sink) override;
 
+  RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet);
+
   // TODO(bugs.webrtc.org/7135): Not yet responsible for parsing.
   bool OnRtpPacket(const RtpPacketReceived& packet);
 
@@ -45,6 +47,8 @@
   // Responsible for demuxing recovered FLEXFEC packets.
   void OnRecoveredPacket(const RtpPacketReceived& packet) override;
 
+  bool IsEmpty() const;
+
  private:
   class Receiver : public RtpStreamReceiverInterface {
    public: