Add/remove receive streams with SSRC 0 from media channels

This enables creation and removal of receive streams with SSRC 0.
Several related methods, for example SetOutputVolume, still use 0 as a
special value.

Bug: webrtc:8694
Change-Id: I341e6bd6c981c9838997510d8d712ad2948f6460
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/152780
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Saurav Das <dinosaurav@chromium.org>
Cr-Commit-Position: refs/heads/master@{#29398}
diff --git a/media/base/fake_media_engine.h b/media/base/fake_media_engine.h
index 28af02a..ac303e6 100644
--- a/media/base/fake_media_engine.h
+++ b/media/base/fake_media_engine.h
@@ -117,6 +117,8 @@
     }
     return RemoveStreamBySsrc(&send_streams_, ssrc);
   }
+  virtual void ResetUnsignaledRecvStream() {}
+
   virtual bool AddRecvStream(const StreamParams& sp) {
     if (absl::c_linear_search(receive_streams_, sp)) {
       return false;
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index d6dfe70..8f6b04b 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -224,6 +224,8 @@
   // ssrc must be the first SSRC of the media stream if the stream uses
   // multiple SSRCs.
   virtual bool RemoveRecvStream(uint32_t ssrc) = 0;
+  // Resets any cached StreamParams for an unsignaled RecvStream.
+  virtual void ResetUnsignaledRecvStream() = 0;
   // Returns the absoulte sendtime extension id value from media channel.
   virtual int GetRtpSendTimeExtnId() const;
   // Set the frame encryptor to use on all outgoing frames. This is optional.
diff --git a/media/base/rtp_data_engine.cc b/media/base/rtp_data_engine.cc
index 33c87cb..6161085 100644
--- a/media/base/rtp_data_engine.cc
+++ b/media/base/rtp_data_engine.cc
@@ -194,6 +194,9 @@
   return true;
 }
 
+// Not implemented.
+void RtpDataMediaChannel::ResetUnsignaledRecvStream() {}
+
 void RtpDataMediaChannel::OnPacketReceived(rtc::CopyOnWriteBuffer packet,
                                            int64_t /* packet_time_us */) {
   RtpHeader header;
diff --git a/media/base/rtp_data_engine.h b/media/base/rtp_data_engine.h
index 60d5f55..e5f071d 100644
--- a/media/base/rtp_data_engine.h
+++ b/media/base/rtp_data_engine.h
@@ -72,6 +72,7 @@
   virtual bool RemoveSendStream(uint32_t ssrc);
   virtual bool AddRecvStream(const StreamParams& sp);
   virtual bool RemoveRecvStream(uint32_t ssrc);
+  virtual void ResetUnsignaledRecvStream();
   virtual bool SetSend(bool send) {
     sending_ = send;
     return true;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 10154d1..96a426d 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -1325,7 +1325,6 @@
     return false;
 
   uint32_t ssrc = sp.first_ssrc();
-  RTC_DCHECK(ssrc != 0);  // TODO(pbos): Is this ever valid?
 
   // Remove running stream if this was a default stream.
   const auto& prev_stream = receive_streams_.find(ssrc);
@@ -1417,12 +1416,6 @@
 bool WebRtcVideoChannel::RemoveRecvStream(uint32_t ssrc) {
   RTC_DCHECK_RUN_ON(&thread_checker_);
   RTC_LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
-  if (ssrc == 0) {
-    // This indicates that we need to remove the unsignaled stream parameters
-    // that are cached.
-    unsignaled_stream_params_ = StreamParams();
-    return true;
-  }
 
   std::map<uint32_t, WebRtcVideoReceiveStream*>::iterator stream =
       receive_streams_.find(ssrc);
@@ -1436,6 +1429,12 @@
   return true;
 }
 
+void WebRtcVideoChannel::ResetUnsignaledRecvStream() {
+  RTC_DCHECK_RUN_ON(&thread_checker_);
+  RTC_LOG(LS_INFO) << "ResetUnsignaledRecvStream.";
+  unsignaled_stream_params_ = StreamParams();
+}
+
 bool WebRtcVideoChannel::SetSink(
     uint32_t ssrc,
     rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h
index 88956e9..b989e22 100644
--- a/media/engine/webrtc_video_engine.h
+++ b/media/engine/webrtc_video_engine.h
@@ -156,6 +156,7 @@
   bool AddRecvStream(const StreamParams& sp) override;
   bool AddRecvStream(const StreamParams& sp, bool default_stream);
   bool RemoveRecvStream(uint32_t ssrc) override;
+  void ResetUnsignaledRecvStream() override;
   bool SetSink(uint32_t ssrc,
                rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) override;
   void FillBitrateInfo(BandwidthEstimationInfo* bwe_info) override;
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index ca2d1a2..1ed3dc3 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -5533,9 +5533,9 @@
   EXPECT_EQ(kSyncLabel,
             fake_call_->GetVideoReceiveStreams()[0]->GetConfig().sync_group);
 
-  // Removing the unsignaled stream should clear the cache. This time when
+  // Reset the unsignaled stream to clear the cache. This time when
   // a default video receive stream is created it won't have a sync_group.
-  ASSERT_TRUE(channel_->RemoveRecvStream(0));
+  channel_->ResetUnsignaledRecvStream();
   ASSERT_TRUE(channel_->RemoveRecvStream(kIncomingUnsignalledSsrc));
   EXPECT_EQ(0u, fake_call_->GetVideoReceiveStreams().size());
 
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index 195ed5b..bef9d23 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -1841,10 +1841,6 @@
   }
 
   const uint32_t ssrc = sp.first_ssrc();
-  if (ssrc == 0) {
-    RTC_DLOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
-    return false;
-  }
 
   // If this stream was previously received unsignaled, we promote it, possibly
   // recreating the AudioReceiveStream, if stream ids have changed.
@@ -1880,13 +1876,6 @@
   RTC_DCHECK(worker_thread_checker_.IsCurrent());
   RTC_LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
 
-  if (ssrc == 0) {
-    // This indicates that we need to remove the unsignaled stream parameters
-    // that are cached.
-    unsignaled_stream_params_ = StreamParams();
-    return true;
-  }
-
   const auto it = recv_streams_.find(ssrc);
   if (it == recv_streams_.end()) {
     RTC_LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
@@ -1902,6 +1891,12 @@
   return true;
 }
 
+void WebRtcVoiceMediaChannel::ResetUnsignaledRecvStream() {
+  RTC_DCHECK(worker_thread_checker_.IsCurrent());
+  RTC_LOG(LS_INFO) << "ResetUnsignaledRecvStream.";
+  unsignaled_stream_params_ = StreamParams();
+}
+
 bool WebRtcVoiceMediaChannel::SetLocalSource(uint32_t ssrc,
                                              AudioSource* source) {
   auto it = send_streams_.find(ssrc);
diff --git a/media/engine/webrtc_voice_engine.h b/media/engine/webrtc_voice_engine.h
index 8990b21..8067ef0 100644
--- a/media/engine/webrtc_voice_engine.h
+++ b/media/engine/webrtc_voice_engine.h
@@ -166,6 +166,7 @@
   bool RemoveSendStream(uint32_t ssrc) override;
   bool AddRecvStream(const StreamParams& sp) override;
   bool RemoveRecvStream(uint32_t ssrc) override;
+  void ResetUnsignaledRecvStream() override;
 
   // E2EE Frame API
   // Set a frame decryptor to a particular ssrc that will intercept all
diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc
index c0f0f2e..8fac2a1 100644
--- a/media/engine/webrtc_voice_engine_unittest.cc
+++ b/media/engine/webrtc_voice_engine_unittest.cc
@@ -2590,9 +2590,9 @@
       GetRecvStream(kSsrc1).VerifyLastPacket(kPcmuFrame, sizeof(kPcmuFrame)));
   EXPECT_EQ(kSyncLabel, GetRecvStream(kSsrc1).GetConfig().sync_group);
 
-  // Removing the unsignaled stream clears the cached parameters. If a new
+  // Remset the unsignaled stream to clear the cached parameters. If a new
   // default unsignaled receive stream is created it will not have a sync group.
-  channel_->RemoveRecvStream(0);
+  channel_->ResetUnsignaledRecvStream();
   channel_->RemoveRecvStream(kSsrc1);
 
   DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
@@ -2763,9 +2763,9 @@
   EXPECT_EQ(0u, call_.GetAudioReceiveStreams().size());
 }
 
-TEST_F(WebRtcVoiceEngineTestFake, TestAddRecvStreamFailWithZeroSsrc) {
+TEST_F(WebRtcVoiceEngineTestFake, TestAddRecvStreamSuccessWithZeroSsrc) {
   EXPECT_TRUE(SetupSendStream());
-  EXPECT_FALSE(AddRecvStream(0));
+  EXPECT_TRUE(AddRecvStream(0));
 }
 
 TEST_F(WebRtcVoiceEngineTestFake, TestAddRecvStreamFailWithSameSsrc) {
diff --git a/pc/channel.cc b/pc/channel.cc
index bcc3d16..8392775 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -580,6 +580,11 @@
   return media_channel()->RemoveRecvStream(ssrc);
 }
 
+void BaseChannel::ResetUnsignaledRecvStream_w() {
+  RTC_DCHECK(worker_thread() == rtc::Thread::Current());
+  media_channel()->ResetUnsignaledRecvStream();
+}
+
 bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
                                        SdpType type,
                                        std::string* error_desc) {
@@ -666,8 +671,11 @@
   for (const StreamParams& old_stream : remote_streams_) {
     // If we no longer have an unsignaled stream, we would like to remove
     // the unsignaled stream params that are cached.
-    if ((!old_stream.has_ssrcs() && !HasStreamWithNoSsrcs(streams)) ||
-        !GetStreamBySsrc(streams, old_stream.first_ssrc())) {
+    if (!old_stream.has_ssrcs() && !HasStreamWithNoSsrcs(streams)) {
+      ResetUnsignaledRecvStream_w();
+      RTC_LOG(LS_INFO) << "Reset unsignaled remote stream.";
+    } else if (old_stream.has_ssrcs() &&
+               !GetStreamBySsrc(streams, old_stream.first_ssrc())) {
       if (RemoveRecvStream_w(old_stream.first_ssrc())) {
         RTC_LOG(LS_INFO) << "Remove remote ssrc: " << old_stream.first_ssrc();
       } else {
@@ -688,10 +696,16 @@
     if ((!new_stream.has_ssrcs() && !HasStreamWithNoSsrcs(remote_streams_)) ||
         !GetStreamBySsrc(remote_streams_, new_stream.first_ssrc())) {
       if (AddRecvStream_w(new_stream)) {
-        RTC_LOG(LS_INFO) << "Add remote ssrc: " << new_stream.first_ssrc();
+        RTC_LOG(LS_INFO) << "Add remote ssrc: "
+                         << (new_stream.has_ssrcs()
+                                 ? std::to_string(new_stream.first_ssrc())
+                                 : "unsignaled");
       } else {
         rtc::StringBuilder desc;
-        desc << "Failed to add remote stream ssrc: " << new_stream.first_ssrc();
+        desc << "Failed to add remote stream ssrc: "
+             << (new_stream.has_ssrcs()
+                     ? std::to_string(new_stream.first_ssrc())
+                     : "unsignaled");
         SafeSetError(desc.str(), error_desc);
         ret = false;
       }
diff --git a/pc/channel.h b/pc/channel.h
index 3b76776..62fcaa2 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -233,6 +233,7 @@
 
   bool AddRecvStream_w(const StreamParams& sp);
   bool RemoveRecvStream_w(uint32_t ssrc);
+  void ResetUnsignaledRecvStream_w();
   bool AddSendStream_w(const StreamParams& sp);
   bool RemoveSendStream_w(uint32_t ssrc);