Move SDP m= line matching from BaseChannel to WebRtcSession

This is part of the work towards implementing Unified Plan.

The logic for correlating m= lines to channels is changing in
Unified Plan. Moving this logic to WebRtcSession means that we do
not need to add a flag to BaseChannel to indicate which logic it
should use (i.e., Plan B vs. Unified Plan) and can keep those
details in WebRtcSession.

Bug: webrtc:8183
Change-Id: I729da73ece01fd20f45e82f8956a02c4cad2469e
Reviewed-on: https://chromium-review.googlesource.com/653490
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Cr-Original-Commit-Position: refs/heads/master@{#19786}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 18ee1d55b4cdd7faef75464e39ec06568790adbc
diff --git a/pc/channel.cc b/pc/channel.cc
index d99a105..8e82925 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -111,13 +111,6 @@
   return direction == MD_SENDRECV || direction == MD_SENDONLY;
 }
 
-static const MediaContentDescription* GetContentDescription(
-    const ContentInfo* cinfo) {
-  if (cinfo == NULL)
-    return NULL;
-  return static_cast<const MediaContentDescription*>(cinfo->description);
-}
-
 template <class Codec>
 void RtpParametersFromMediaDescription(
     const MediaContentDescriptionImpl<Codec>* desc,
@@ -746,34 +739,6 @@
   }
 }
 
-bool BaseChannel::PushdownLocalDescription(
-    const SessionDescription* local_desc, ContentAction action,
-    std::string* error_desc) {
-  const ContentInfo* content_info = GetFirstContent(local_desc);
-  const MediaContentDescription* content_desc =
-      GetContentDescription(content_info);
-  if (content_desc && content_info && !content_info->rejected &&
-      !SetLocalContent(content_desc, action, error_desc)) {
-    LOG(LS_ERROR) << "Failure in SetLocalContent with action " << action;
-    return false;
-  }
-  return true;
-}
-
-bool BaseChannel::PushdownRemoteDescription(
-    const SessionDescription* remote_desc, ContentAction action,
-    std::string* error_desc) {
-  const ContentInfo* content_info = GetFirstContent(remote_desc);
-  const MediaContentDescription* content_desc =
-      GetContentDescription(content_info);
-  if (content_desc && content_info && !content_info->rejected &&
-      !SetRemoteContent(content_desc, action, error_desc)) {
-    LOG(LS_ERROR) << "Failure in SetRemoteContent with action " << action;
-    return false;
-  }
-  return true;
-}
-
 void BaseChannel::EnableMedia_w() {
   RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
   if (enabled_)
@@ -1728,11 +1693,6 @@
   LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
 }
 
-const ContentInfo* VoiceChannel::GetFirstContent(
-    const SessionDescription* sdesc) {
-  return GetFirstAudioContent(sdesc);
-}
-
 bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
                                      ContentAction action,
                                      std::string* error_desc) {
@@ -2015,11 +1975,6 @@
   }
 }
 
-const ContentInfo* VideoChannel::GetFirstContent(
-    const SessionDescription* sdesc) {
-  return GetFirstVideoContent(sdesc);
-}
-
 bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
                                      ContentAction action,
                                      std::string* error_desc) {
@@ -2201,11 +2156,6 @@
                           payload, result));
 }
 
-const ContentInfo* RtpDataChannel::GetFirstContent(
-    const SessionDescription* sdesc) {
-  return GetFirstDataContent(sdesc);
-}
-
 bool RtpDataChannel::CheckDataChannelTypeFromContent(
     const DataContentDescription* content,
     std::string* error_desc) {
diff --git a/pc/channel.h b/pc/channel.h
index b95bd52..4ff21fe 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -121,12 +121,6 @@
                      DtlsTransportInternal* rtcp_dtls_transport);
   void SetTransports(rtc::PacketTransportInternal* rtp_packet_transport,
                      rtc::PacketTransportInternal* rtcp_packet_transport);
-  bool PushdownLocalDescription(const SessionDescription* local_desc,
-                                ContentAction action,
-                                std::string* error_desc);
-  bool PushdownRemoteDescription(const SessionDescription* remote_desc,
-                                ContentAction action,
-                                std::string* error_desc);
   // Channel control
   bool SetLocalContent(const MediaContentDescription* content,
                        ContentAction action,
@@ -302,9 +296,6 @@
   void UpdateMediaSendRecvState();
   virtual void UpdateMediaSendRecvState_w() = 0;
 
-  // Gets the content info appropriate to the channel (audio or video).
-  virtual const ContentInfo* GetFirstContent(
-      const SessionDescription* sdesc) = 0;
   bool UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
                             ContentAction action,
                             std::string* error_desc);
@@ -509,7 +500,6 @@
                         rtc::CopyOnWriteBuffer* packet,
                         const rtc::PacketTime& packet_time) override;
   void UpdateMediaSendRecvState_w() override;
-  const ContentInfo* GetFirstContent(const SessionDescription* sdesc) override;
   bool SetLocalContent_w(const MediaContentDescription* content,
                          ContentAction action,
                          std::string* error_desc) override;
@@ -589,7 +579,6 @@
  private:
   // overrides from BaseChannel
   void UpdateMediaSendRecvState_w() override;
-  const ContentInfo* GetFirstContent(const SessionDescription* sdesc) override;
   bool SetLocalContent_w(const MediaContentDescription* content,
                          ContentAction action,
                          std::string* error_desc) override;
@@ -699,7 +688,6 @@
   typedef rtc::TypedMessageData<bool> DataChannelReadyToSendMessageData;
 
   // overrides from BaseChannel
-  const ContentInfo* GetFirstContent(const SessionDescription* sdesc) override;
   // Checks that data channel type is RTP.
   bool CheckDataChannelTypeFromContent(const DataContentDescription* content,
                                        std::string* error_desc);
diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc
index 5279683..b16e60d 100644
--- a/pc/channel_unittest.cc
+++ b/pc/channel_unittest.cc
@@ -511,17 +511,13 @@
     // overridden in specialized classes
   }
 
-  // Creates a cricket::SessionDescription with one MediaContent and one stream.
+  // Creates a MediaContent with one stream.
   // kPcmuCodec is used as audio codec and kH264Codec is used as video codec.
-  cricket::SessionDescription* CreateSessionDescriptionWithStream(
-      uint32_t ssrc) {
-     typename T::Content content;
-     cricket::SessionDescription* sdesc = new cricket::SessionDescription();
-     CreateContent(SECURE, kPcmuCodec, kH264Codec, &content);
-     AddLegacyStreamInContent(ssrc, 0, &content);
-     sdesc->AddContent("DUMMY_CONTENT_NAME",
-                       cricket::NS_JINGLE_RTP, content.Copy());
-     return sdesc;
+  typename T::Content* CreateMediaContentWithStream(uint32_t ssrc) {
+    typename T::Content* content = new typename T::Content();
+    CreateContent(SECURE, kPcmuCodec, kH264Codec, content);
+    AddLegacyStreamInContent(ssrc, 0, content);
+    return content;
   }
 
   // Will manage the lifetime of a CallThread, making sure it's
@@ -1829,41 +1825,39 @@
   void TestSetContentFailure() {
     CreateChannels(0, 0);
 
-    auto sdesc = cricket::SessionDescription();
-    sdesc.AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP,
-                     new cricket::AudioContentDescription());
-    sdesc.AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP,
-                     new cricket::VideoContentDescription());
-
     std::string err;
+    std::unique_ptr<typename T::Content> content(
+        CreateMediaContentWithStream(1));
+
     media_channel1_->set_fail_set_recv_codecs(true);
-    EXPECT_FALSE(channel1_->PushdownLocalDescription(
-        &sdesc, cricket::CA_OFFER, &err));
-    EXPECT_FALSE(channel1_->PushdownLocalDescription(
-        &sdesc, cricket::CA_ANSWER, &err));
+    EXPECT_FALSE(
+        channel1_->SetLocalContent(content.get(), cricket::CA_OFFER, &err));
+    EXPECT_FALSE(
+        channel1_->SetLocalContent(content.get(), cricket::CA_ANSWER, &err));
 
     media_channel1_->set_fail_set_send_codecs(true);
-    EXPECT_FALSE(channel1_->PushdownRemoteDescription(
-        &sdesc, cricket::CA_OFFER, &err));
+    EXPECT_FALSE(
+        channel1_->SetRemoteContent(content.get(), cricket::CA_OFFER, &err));
+
     media_channel1_->set_fail_set_send_codecs(true);
-    EXPECT_FALSE(channel1_->PushdownRemoteDescription(
-        &sdesc, cricket::CA_ANSWER, &err));
+    EXPECT_FALSE(
+        channel1_->SetRemoteContent(content.get(), cricket::CA_ANSWER, &err));
   }
 
   void TestSendTwoOffers() {
     CreateChannels(0, 0);
 
     std::string err;
-    std::unique_ptr<cricket::SessionDescription> sdesc1(
-        CreateSessionDescriptionWithStream(1));
-    EXPECT_TRUE(channel1_->PushdownLocalDescription(
-        sdesc1.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content1(
+        CreateMediaContentWithStream(1));
+    EXPECT_TRUE(
+        channel1_->SetLocalContent(content1.get(), cricket::CA_OFFER, &err));
     EXPECT_TRUE(media_channel1_->HasSendStream(1));
 
-    std::unique_ptr<cricket::SessionDescription> sdesc2(
-        CreateSessionDescriptionWithStream(2));
-    EXPECT_TRUE(channel1_->PushdownLocalDescription(
-        sdesc2.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content2(
+        CreateMediaContentWithStream(2));
+    EXPECT_TRUE(
+        channel1_->SetLocalContent(content2.get(), cricket::CA_OFFER, &err));
     EXPECT_FALSE(media_channel1_->HasSendStream(1));
     EXPECT_TRUE(media_channel1_->HasSendStream(2));
   }
@@ -1872,16 +1866,16 @@
     CreateChannels(0, 0);
 
     std::string err;
-    std::unique_ptr<cricket::SessionDescription> sdesc1(
-        CreateSessionDescriptionWithStream(1));
-    EXPECT_TRUE(channel1_->PushdownRemoteDescription(
-        sdesc1.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content1(
+        CreateMediaContentWithStream(1));
+    EXPECT_TRUE(
+        channel1_->SetRemoteContent(content1.get(), cricket::CA_OFFER, &err));
     EXPECT_TRUE(media_channel1_->HasRecvStream(1));
 
-    std::unique_ptr<cricket::SessionDescription> sdesc2(
-        CreateSessionDescriptionWithStream(2));
-    EXPECT_TRUE(channel1_->PushdownRemoteDescription(
-        sdesc2.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content2(
+        CreateMediaContentWithStream(2));
+    EXPECT_TRUE(
+        channel1_->SetRemoteContent(content2.get(), cricket::CA_OFFER, &err));
     EXPECT_FALSE(media_channel1_->HasRecvStream(1));
     EXPECT_TRUE(media_channel1_->HasRecvStream(2));
   }
@@ -1891,25 +1885,25 @@
 
     std::string err;
     // Receive offer
-    std::unique_ptr<cricket::SessionDescription> sdesc1(
-        CreateSessionDescriptionWithStream(1));
-    EXPECT_TRUE(channel1_->PushdownRemoteDescription(
-        sdesc1.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content1(
+        CreateMediaContentWithStream(1));
+    EXPECT_TRUE(
+        channel1_->SetRemoteContent(content1.get(), cricket::CA_OFFER, &err));
     EXPECT_TRUE(media_channel1_->HasRecvStream(1));
 
     // Send PR answer
-    std::unique_ptr<cricket::SessionDescription> sdesc2(
-        CreateSessionDescriptionWithStream(2));
-    EXPECT_TRUE(channel1_->PushdownLocalDescription(
-        sdesc2.get(), cricket::CA_PRANSWER, &err));
+    std::unique_ptr<typename T::Content> content2(
+        CreateMediaContentWithStream(2));
+    EXPECT_TRUE(
+        channel1_->SetLocalContent(content2.get(), cricket::CA_PRANSWER, &err));
     EXPECT_TRUE(media_channel1_->HasRecvStream(1));
     EXPECT_TRUE(media_channel1_->HasSendStream(2));
 
     // Send answer
-    std::unique_ptr<cricket::SessionDescription> sdesc3(
-        CreateSessionDescriptionWithStream(3));
-    EXPECT_TRUE(channel1_->PushdownLocalDescription(
-        sdesc3.get(), cricket::CA_ANSWER, &err));
+    std::unique_ptr<typename T::Content> content3(
+        CreateMediaContentWithStream(3));
+    EXPECT_TRUE(
+        channel1_->SetLocalContent(content3.get(), cricket::CA_ANSWER, &err));
     EXPECT_TRUE(media_channel1_->HasRecvStream(1));
     EXPECT_FALSE(media_channel1_->HasSendStream(2));
     EXPECT_TRUE(media_channel1_->HasSendStream(3));
@@ -1920,25 +1914,25 @@
 
     std::string err;
     // Send offer
-    std::unique_ptr<cricket::SessionDescription> sdesc1(
-        CreateSessionDescriptionWithStream(1));
-    EXPECT_TRUE(channel1_->PushdownLocalDescription(
-        sdesc1.get(), cricket::CA_OFFER, &err));
+    std::unique_ptr<typename T::Content> content1(
+        CreateMediaContentWithStream(1));
+    EXPECT_TRUE(
+        channel1_->SetLocalContent(content1.get(), cricket::CA_OFFER, &err));
     EXPECT_TRUE(media_channel1_->HasSendStream(1));
 
     // Receive PR answer
-    std::unique_ptr<cricket::SessionDescription> sdesc2(
-        CreateSessionDescriptionWithStream(2));
-    EXPECT_TRUE(channel1_->PushdownRemoteDescription(
-        sdesc2.get(), cricket::CA_PRANSWER, &err));
+    std::unique_ptr<typename T::Content> content2(
+        CreateMediaContentWithStream(2));
+    EXPECT_TRUE(channel1_->SetRemoteContent(content2.get(),
+                                            cricket::CA_PRANSWER, &err));
     EXPECT_TRUE(media_channel1_->HasSendStream(1));
     EXPECT_TRUE(media_channel1_->HasRecvStream(2));
 
     // Receive answer
-    std::unique_ptr<cricket::SessionDescription> sdesc3(
-        CreateSessionDescriptionWithStream(3));
-    EXPECT_TRUE(channel1_->PushdownRemoteDescription(
-        sdesc3.get(), cricket::CA_ANSWER, &err));
+    std::unique_ptr<typename T::Content> content3(
+        CreateMediaContentWithStream(3));
+    EXPECT_TRUE(
+        channel1_->SetRemoteContent(content3.get(), cricket::CA_ANSWER, &err));
     EXPECT_TRUE(media_channel1_->HasSendStream(1));
     EXPECT_FALSE(media_channel1_->HasRecvStream(2));
     EXPECT_TRUE(media_channel1_->HasRecvStream(3));
diff --git a/pc/webrtcsession.cc b/pc/webrtcsession.cc
index b423663..c78dbc4 100644
--- a/pc/webrtcsession.cc
+++ b/pc/webrtcsession.cc
@@ -847,6 +847,21 @@
   return true;
 }
 
+// TODO(steveanton): Eventually it'd be nice to store the channels as a single
+// vector of BaseChannel pointers instead of separate voice and video channel
+// vectors. At that point, this will become a simple getter.
+std::vector<cricket::BaseChannel*> WebRtcSession::Channels() const {
+  std::vector<cricket::BaseChannel*> channels;
+  channels.insert(channels.end(), voice_channels_.begin(),
+                  voice_channels_.end());
+  channels.insert(channels.end(), video_channels_.begin(),
+                  video_channels_.end());
+  if (rtp_data_channel_) {
+    channels.push_back(rtp_data_channel_.get());
+  }
+  return channels;
+}
+
 void WebRtcSession::LogState(State old_state, State new_state) {
   LOG(LS_INFO) << "Session:" << id()
                << " Old state:" << GetStateString(old_state)
@@ -953,30 +968,40 @@
     cricket::ContentAction action,
     cricket::ContentSource source,
     std::string* err) {
-  auto set_content = [this, action, source, err](cricket::BaseChannel* ch) {
-    if (!ch) {
-      return true;
-    } else if (source == cricket::CS_LOCAL) {
-      return ch->PushdownLocalDescription(local_description()->description(),
-                                          action, err);
-    } else {
-      return ch->PushdownRemoteDescription(remote_description()->description(),
-                                           action, err);
+  const SessionDescription* sdesc =
+      (source == cricket::CS_LOCAL ? local_description() : remote_description())
+          ->description();
+  RTC_DCHECK(sdesc);
+  bool all_success = true;
+  for (auto* channel : Channels()) {
+    // TODO(steveanton): Add support for multiple channels of the same type.
+    const ContentInfo* content_info =
+        cricket::GetFirstMediaContent(sdesc->contents(), channel->media_type());
+    if (!content_info) {
+      continue;
     }
-  };
-
-  bool ret = (set_content(voice_channel()) && set_content(video_channel()) &&
-              set_content(rtp_data_channel()));
+    const MediaContentDescription* content_desc =
+        static_cast<const MediaContentDescription*>(content_info->description);
+    if (content_desc && !content_info->rejected) {
+      bool success = (source == cricket::CS_LOCAL)
+                         ? channel->SetLocalContent(content_desc, action, err)
+                         : channel->SetRemoteContent(content_desc, action, err);
+      if (!success) {
+        all_success = false;
+        break;
+      }
+    }
+  }
   // Need complete offer/answer with an SCTP m= section before starting SCTP,
   // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
   if (sctp_transport_ && local_description() && remote_description() &&
       cricket::GetFirstDataContent(local_description()->description()) &&
       cricket::GetFirstDataContent(remote_description()->description())) {
-    ret &= network_thread_->Invoke<bool>(
+    all_success &= network_thread_->Invoke<bool>(
         RTC_FROM_HERE,
         rtc::Bind(&WebRtcSession::PushdownSctpParameters_n, this, source));
   }
-  return ret;
+  return all_success;
 }
 
 bool WebRtcSession::PushdownSctpParameters_n(cricket::ContentSource source) {
diff --git a/pc/webrtcsession.h b/pc/webrtcsession.h
index 4d52a5c..686ac1e 100644
--- a/pc/webrtcsession.h
+++ b/pc/webrtcsession.h
@@ -393,6 +393,9 @@
     kAnswer,
   };
 
+  // Return all managed, non-null channels.
+  std::vector<cricket::BaseChannel*> Channels() const;
+
   // Non-const versions of local_description()/remote_description(), for use
   // internally.
   SessionDescriptionInterface* mutable_local_description() {