Revert "Reland "Refactoring DataContentDescription class""

This reverts commit 26bf7c4682c7ec72465a1d4d6485d2ec01f671cc.

Reason for revert: breaks downstream test

Original change's description:
> Reland "Refactoring DataContentDescription class"
> 
> This reverts commit 1859dc04fd8bd35a3d2ee1140bde3eac210bb0c2.
> 
> Reason for revert: Issue likely unrelated to this CL.
> 
> Original change's description:
> > Revert "Refactoring DataContentDescription class"
> >
> > This reverts commit 8a9193c217d818fea77b9540bd4ca7ebad53db76.
> >
> > Reason for revert: Breaks downstreams
> >
> > Original change's description:
> > > Refactoring DataContentDescription class
> > >
> > > This CL splits the cricket::DataContentDescription class into
> > > two classes: cricket::DataContentDescription (used for RTP data) and
> > > cricket::SctpDataContentDescription (used for SCTP only).
> > >
> > > SctpDataContentDescription no longer inherits from
> > > MediaContentDescriptionImpl, and no longer contains "codecs".
> > >
> > > Design document:
> > > https://docs.google.com/document/d/1H5LfQxJA2ikMWTQ8FZ3_GAmaXM7knfVQWiSz6ph8VQ0/edit#
> > >
> > > Bug: webrtc:10358
> > > Change-Id: Ie7160610506aeef56d1f821b5fdb5d9492201f43
> > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/132700
> > > Reviewed-by: Steve Anton <steveanton@webrtc.org>
> > > Commit-Queue: Harald Alvestrand <hta@webrtc.org>
> > > Cr-Commit-Position: refs/heads/master@{#27651}
> >
> > TBR=steveanton@webrtc.org,kwiberg@webrtc.org,hbos@webrtc.org,hta@webrtc.org
> >
> > Change-Id: I3b8a68cd481c41ce30eeb5ffbc5da735a9659019
> > No-Presubmit: true
> > No-Tree-Checks: true
> > No-Try: true
> > Bug: webrtc:10358
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133360
> > Reviewed-by: Seth Hampson <shampson@webrtc.org>
> > Commit-Queue: Seth Hampson <shampson@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#27652}
> 
> # Not skipping CQ checks because original CL landed > 1 day ago.
> 
> Bug: webrtc:10358
> Change-Id: Ie58f862f8c55d2a994eaee1caa107ef701b0770f
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133624
> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
> Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> Commit-Queue: Harald Alvestrand <hta@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#27698}

TBR=danilchap@webrtc.org,steveanton@webrtc.org,kwiberg@webrtc.org,hbos@webrtc.org,hta@webrtc.org,shampson@webrtc.org

Change-Id: Ib17939d5f1e8c57652dcb34d94866654192379bb
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:10358
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133880
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27702}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 7a28d88..4a4a7af 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -72,7 +72,6 @@
   ]
 
   deps = [
-    ":media_protocol_names",
     "../api:array_view",
     "../api:audio_options_api",
     "../api:call_api",
@@ -122,13 +121,6 @@
   ]
 }
 
-rtc_source_set("media_protocol_names") {
-  sources = [
-    "media_protocol_names.cc",
-    "media_protocol_names.h",
-  ]
-}
-
 rtc_static_library("peerconnection") {
   visibility = [ "*" ]
   cflags = []
diff --git a/pc/media_protocol_names.cc b/pc/media_protocol_names.cc
deleted file mode 100644
index 6ce2f02..0000000
--- a/pc/media_protocol_names.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "pc/media_protocol_names.h"
-
-namespace cricket {
-
-const char kMediaProtocolRtpPrefix[] = "RTP/";
-
-const char kMediaProtocolSctp[] = "SCTP";
-const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
-const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
-const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
-
-bool IsDtlsSctp(const std::string& protocol) {
-  return protocol == kMediaProtocolDtlsSctp ||
-         protocol == kMediaProtocolUdpDtlsSctp ||
-         protocol == kMediaProtocolTcpDtlsSctp;
-}
-
-bool IsPlainSctp(const std::string& protocol) {
-  return protocol == kMediaProtocolSctp;
-}
-
-bool IsRtpProtocol(const std::string& protocol) {
-  return protocol.empty() ||
-         (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
-}
-
-bool IsSctpProtocol(const std::string& protocol) {
-  return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
-}
-
-}  // namespace cricket
diff --git a/pc/media_protocol_names.h b/pc/media_protocol_names.h
deleted file mode 100644
index f97055d..0000000
--- a/pc/media_protocol_names.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef PC_MEDIA_PROTOCOL_NAMES_H_
-#define PC_MEDIA_PROTOCOL_NAMES_H_
-
-#include <string>
-
-namespace cricket {
-
-// Names or name prefixes of protocols as defined by SDP specifications.
-extern const char kMediaProtocolRtpPrefix[];
-extern const char kMediaProtocolSctp[];
-extern const char kMediaProtocolDtlsSctp[];
-extern const char kMediaProtocolUdpDtlsSctp[];
-extern const char kMediaProtocolTcpDtlsSctp[];
-
-// Returns true if the given media section protocol indicates use of RTP.
-bool IsRtpProtocol(const std::string& protocol);
-// Returns true if the given media section protocol indicates use of SCTP.
-bool IsSctpProtocol(const std::string& protocol);
-
-bool IsDtlsSctp(const std::string& protocol);
-bool IsPlainSctp(const std::string& protocol);
-
-}  // namespace cricket
-
-#endif  // PC_MEDIA_PROTOCOL_NAMES_H_
diff --git a/pc/media_session.cc b/pc/media_session.cc
index b739e90..8377f10 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -27,7 +27,6 @@
 #include "media/base/media_constants.h"
 #include "p2p/base/p2p_constants.h"
 #include "pc/channel_manager.h"
-#include "pc/media_protocol_names.h"
 #include "pc/rtp_media_utils.h"
 #include "pc/srtp_filter.h"
 #include "rtc_base/checks.h"
@@ -69,6 +68,13 @@
 // but we tolerate "RTP/SAVPF" in offers we receive, for compatibility.
 const char kMediaProtocolSavpf[] = "RTP/SAVPF";
 
+const char kMediaProtocolRtpPrefix[] = "RTP/";
+
+const char kMediaProtocolSctp[] = "SCTP";
+const char kMediaProtocolDtlsSctp[] = "DTLS/SCTP";
+const char kMediaProtocolUdpDtlsSctp[] = "UDP/DTLS/SCTP";
+const char kMediaProtocolTcpDtlsSctp[] = "TCP/DTLS/SCTP";
+
 // Note that the below functions support some protocol strings purely for
 // legacy compatibility, as required by JSEP in Section 5.1.2, Profile Names
 // and Interoperability.
@@ -85,6 +91,20 @@
          protocol == "RTP/SAVP" || protocol == "RTP/AVP";
 }
 
+static bool IsDtlsSctp(const std::string& protocol) {
+  return protocol == kMediaProtocolDtlsSctp ||
+         protocol == kMediaProtocolUdpDtlsSctp ||
+         protocol == kMediaProtocolTcpDtlsSctp;
+}
+
+static bool IsPlainSctp(const std::string& protocol) {
+  return protocol == kMediaProtocolSctp;
+}
+
+static bool IsSctp(const std::string& protocol) {
+  return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
+}
+
 static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
     RtpTransceiverDirection offer,
     RtpTransceiverDirection wants) {
@@ -469,7 +489,7 @@
     StreamParamsVec* current_streams,
     MediaContentDescriptionImpl<C>* content_description) {
   // SCTP streams are not negotiated using SDP/ContentDescriptions.
-  if (IsSctpProtocol(content_description->protocol())) {
+  if (IsSctp(content_description->protocol())) {
     return true;
   }
 
@@ -588,6 +608,11 @@
       target_cryptos->end());
 }
 
+bool IsRtpProtocol(const std::string& protocol) {
+  return protocol.empty() ||
+         (protocol.find(cricket::kMediaProtocolRtpPrefix) != std::string::npos);
+}
+
 static bool IsRtpContent(SessionDescription* sdesc,
                          const std::string& content_name) {
   bool is_rtp = false;
@@ -716,22 +741,32 @@
 // crypto (in current_cryptos) and it is enabled (in secure_policy), crypto is
 // created (according to crypto_suites). The created content is added to the
 // offer.
-static bool CreateContentOffer(
+template <class C>
+static bool CreateMediaContentOffer(
     const MediaDescriptionOptions& media_description_options,
     const MediaSessionOptions& session_options,
+    const std::vector<C>& codecs,
     const SecurePolicy& secure_policy,
     const CryptoParamsVec* current_cryptos,
     const std::vector<std::string>& crypto_suites,
     const RtpHeaderExtensions& rtp_extensions,
     UniqueRandomIdGenerator* ssrc_generator,
     StreamParamsVec* current_streams,
-    MediaContentDescription* offer) {
+    MediaContentDescriptionImpl<C>* offer) {
+  offer->AddCodecs(codecs);
+
   offer->set_rtcp_mux(session_options.rtcp_mux_enabled);
   if (offer->type() == cricket::MEDIA_TYPE_VIDEO) {
     offer->set_rtcp_reduced_size(true);
   }
   offer->set_rtp_header_extensions(rtp_extensions);
 
+  if (!AddStreamParams(media_description_options.sender_options,
+                       session_options.rtcp_cname, ssrc_generator,
+                       current_streams, offer)) {
+    return false;
+  }
+
   AddSimulcastToMediaDescription(media_description_options, offer);
 
   if (secure_policy != SEC_DISABLED) {
@@ -750,30 +785,6 @@
   }
   return true;
 }
-template <class C>
-static bool CreateMediaContentOffer(
-    const MediaDescriptionOptions& media_description_options,
-    const MediaSessionOptions& session_options,
-    const std::vector<C>& codecs,
-    const SecurePolicy& secure_policy,
-    const CryptoParamsVec* current_cryptos,
-    const std::vector<std::string>& crypto_suites,
-    const RtpHeaderExtensions& rtp_extensions,
-    UniqueRandomIdGenerator* ssrc_generator,
-    StreamParamsVec* current_streams,
-    MediaContentDescriptionImpl<C>* offer) {
-  offer->AddCodecs(codecs);
-  if (!AddStreamParams(media_description_options.sender_options,
-                       session_options.rtcp_cname, ssrc_generator,
-                       current_streams, offer)) {
-    return false;
-  }
-
-  return CreateContentOffer(media_description_options, session_options,
-                            secure_policy, current_cryptos, crypto_suites,
-                            rtp_extensions, ssrc_generator, current_streams,
-                            offer);
-}
 
 template <class C>
 static bool ReferencedCodecsMatch(const std::vector<C>& codecs1,
@@ -1126,27 +1137,6 @@
                       audio_codecs->end());
 }
 
-template <class C>
-static bool SetCodecsInAnswer(
-    const MediaContentDescriptionImpl<C>* offer,
-    const std::vector<C>& local_codecs,
-    const MediaDescriptionOptions& media_description_options,
-    const MediaSessionOptions& session_options,
-    UniqueRandomIdGenerator* ssrc_generator,
-    StreamParamsVec* current_streams,
-    MediaContentDescriptionImpl<C>* answer) {
-  std::vector<C> negotiated_codecs;
-  NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
-  answer->AddCodecs(negotiated_codecs);
-  answer->set_protocol(offer->protocol());
-  if (!AddStreamParams(media_description_options.sender_options,
-                       session_options.rtcp_cname, ssrc_generator,
-                       current_streams, answer)) {
-    return false;  // Something went seriously wrong.
-  }
-  return true;
-}
-
 // Create a media content to be answered for the given |sender_options|
 // according to the given session_options.rtcp_mux, session_options.streams,
 // codecs, crypto, and current_streams.  If we don't currently have crypto (in
@@ -1154,10 +1144,12 @@
 // (according to crypto_suites). The codecs, rtcp_mux, and crypto are all
 // negotiated with the offer. If the negotiation fails, this method returns
 // false.  The created content is added to the offer.
+template <class C>
 static bool CreateMediaContentAnswer(
-    const MediaContentDescription* offer,
+    const MediaContentDescriptionImpl<C>* offer,
     const MediaDescriptionOptions& media_description_options,
     const MediaSessionOptions& session_options,
+    const std::vector<C>& local_codecs,
     const SecurePolicy& sdes_policy,
     const CryptoParamsVec* current_cryptos,
     const RtpHeaderExtensions& local_rtp_extenstions,
@@ -1165,7 +1157,12 @@
     bool enable_encrypted_rtp_header_extensions,
     StreamParamsVec* current_streams,
     bool bundle_enabled,
-    MediaContentDescription* answer) {
+    MediaContentDescriptionImpl<C>* answer) {
+  std::vector<C> negotiated_codecs;
+  NegotiateCodecs(local_codecs, offer->codecs(), &negotiated_codecs);
+  answer->AddCodecs(negotiated_codecs);
+  answer->set_protocol(offer->protocol());
+
   answer->set_extmap_allow_mixed_enum(offer->extmap_allow_mixed_enum());
   RtpHeaderExtensions negotiated_rtp_extensions;
   NegotiateRtpHeaderExtensions(
@@ -1193,6 +1190,12 @@
     return false;
   }
 
+  if (!AddStreamParams(media_description_options.sender_options,
+                       session_options.rtcp_cname, ssrc_generator,
+                       current_streams, answer)) {
+    return false;  // Something went seriously wrong.
+  }
+
   AddSimulcastToMediaDescription(media_description_options, answer);
 
   answer->set_direction(NegotiateRtpTransceiverDirection(
@@ -1777,10 +1780,7 @@
     } else if (IsMediaContentOfType(content, MEDIA_TYPE_DATA)) {
       const DataContentDescription* data =
           content->media_description()->as_data();
-      if (data) {
-        // Only relevant for RTP datachannels
-        MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
-      }
+      MergeCodecs<DataCodec>(data->codecs(), data_codecs, used_pltypes);
     }
   }
 }
@@ -1861,16 +1861,13 @@
     } else if (IsMediaContentOfType(&content, MEDIA_TYPE_DATA)) {
       const DataContentDescription* data =
           content.media_description()->as_data();
-      if (data) {
-        // RTP data. This part is inactive for SCTP data.
-        for (const DataCodec& offered_data_codec : data->codecs()) {
-          if (!FindMatchingCodec<DataCodec>(data->codecs(),
-                                            filtered_offered_data_codecs,
-                                            offered_data_codec, nullptr) &&
-              FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
-                                           offered_data_codec, nullptr)) {
-            filtered_offered_data_codecs.push_back(offered_data_codec);
-          }
+      for (const DataCodec& offered_data_codec : data->codecs()) {
+        if (!FindMatchingCodec<DataCodec>(data->codecs(),
+                                          filtered_offered_data_codecs,
+                                          offered_data_codec, nullptr) &&
+            FindMatchingCodec<DataCodec>(data->codecs(), data_codecs_,
+                                         offered_data_codec, nullptr)) {
+          filtered_offered_data_codecs.push_back(offered_data_codec);
         }
       }
     }
@@ -2143,90 +2140,6 @@
   return true;
 }
 
-bool MediaSessionDescriptionFactory::AddSctpDataContentForOffer(
-    const MediaDescriptionOptions& media_description_options,
-    const MediaSessionOptions& session_options,
-    const ContentInfo* current_content,
-    const SessionDescription* current_description,
-    StreamParamsVec* current_streams,
-    SessionDescription* desc,
-    IceCredentialsIterator* ice_credentials) const {
-  std::unique_ptr<SctpDataContentDescription> data(
-      new SctpDataContentDescription());
-
-  bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
-
-  cricket::SecurePolicy sdes_policy =
-      IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
-                                                         : secure();
-  std::vector<std::string> crypto_suites;
-  // SDES doesn't make sense for SCTP, so we disable it, and we only
-  // get SDES crypto suites for RTP-based data channels.
-  sdes_policy = cricket::SEC_DISABLED;
-  // Unlike SetMediaProtocol below, we need to set the protocol
-  // before we call CreateMediaContentOffer.  Otherwise,
-  // CreateMediaContentOffer won't know this is SCTP and will
-  // generate SSRCs rather than SIDs.
-  // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
-  // it's safe to do so. Older versions of webrtc would reject these
-  // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
-  data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
-                                      : kMediaProtocolSctp);
-
-  if (!CreateContentOffer(media_description_options, session_options,
-                          sdes_policy, GetCryptos(current_content),
-                          crypto_suites, RtpHeaderExtensions(), ssrc_generator_,
-                          current_streams, data.get())) {
-    return false;
-  }
-
-  desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
-                   data.release());
-  if (!AddTransportOffer(media_description_options.mid,
-                         media_description_options.transport_options,
-                         current_description, desc, ice_credentials)) {
-    return false;
-  }
-  return true;
-}
-
-bool MediaSessionDescriptionFactory::AddRtpDataContentForOffer(
-    const MediaDescriptionOptions& media_description_options,
-    const MediaSessionOptions& session_options,
-    const ContentInfo* current_content,
-    const SessionDescription* current_description,
-    const DataCodecs& data_codecs,
-    StreamParamsVec* current_streams,
-    SessionDescription* desc,
-    IceCredentialsIterator* ice_credentials) const {
-  std::unique_ptr<DataContentDescription> data(new DataContentDescription());
-  bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
-
-  cricket::SecurePolicy sdes_policy =
-      IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
-                                                         : secure();
-  std::vector<std::string> crypto_suites;
-    GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
-                                         &crypto_suites);
-  if (!CreateMediaContentOffer(
-          media_description_options, session_options, data_codecs, sdes_policy,
-          GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
-          ssrc_generator_, current_streams, data.get())) {
-    return false;
-  }
-
-  data->set_bandwidth(kDataMaxBandwidth);
-  SetMediaProtocol(secure_transport, data.get());
-  desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
-                   media_description_options.stopped, data.release());
-  if (!AddTransportOffer(media_description_options.mid,
-                         media_description_options.transport_options,
-                         current_description, desc, ice_credentials)) {
-    return false;
-  }
-  return true;
-}
-
 bool MediaSessionDescriptionFactory::AddDataContentForOffer(
     const MediaDescriptionOptions& media_description_options,
     const MediaSessionOptions& session_options,
@@ -2236,6 +2149,9 @@
     StreamParamsVec* current_streams,
     SessionDescription* desc,
     IceCredentialsIterator* ice_credentials) const {
+  bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
+
+  std::unique_ptr<DataContentDescription> data(new DataContentDescription());
   bool is_sctp = (session_options.data_channel_type == DCT_SCTP);
   // If the DataChannel type is not specified, use the DataChannel type in
   // the current description.
@@ -2244,16 +2160,52 @@
     is_sctp = (current_content->media_description()->protocol() ==
                kMediaProtocolSctp);
   }
+
+  cricket::SecurePolicy sdes_policy =
+      IsDtlsActive(current_content, current_description) ? cricket::SEC_DISABLED
+                                                         : secure();
+  std::vector<std::string> crypto_suites;
   if (is_sctp) {
-    return AddSctpDataContentForOffer(
-        media_description_options, session_options, current_content,
-        current_description, current_streams, desc, ice_credentials);
+    // SDES doesn't make sense for SCTP, so we disable it, and we only
+    // get SDES crypto suites for RTP-based data channels.
+    sdes_policy = cricket::SEC_DISABLED;
+    // Unlike SetMediaProtocol below, we need to set the protocol
+    // before we call CreateMediaContentOffer.  Otherwise,
+    // CreateMediaContentOffer won't know this is SCTP and will
+    // generate SSRCs rather than SIDs.
+    // TODO(deadbeef): Offer kMediaProtocolUdpDtlsSctp (or TcpDtlsSctp), once
+    // it's safe to do so. Older versions of webrtc would reject these
+    // protocols; see https://bugs.chromium.org/p/webrtc/issues/detail?id=7706.
+    data->set_protocol(secure_transport ? kMediaProtocolDtlsSctp
+                                        : kMediaProtocolSctp);
   } else {
-    return AddRtpDataContentForOffer(media_description_options, session_options,
-                                     current_content, current_description,
-                                     data_codecs, current_streams, desc,
-                                     ice_credentials);
+    GetSupportedDataSdesCryptoSuiteNames(session_options.crypto_options,
+                                         &crypto_suites);
   }
+
+  // Even SCTP uses a "codec".
+  if (!CreateMediaContentOffer(
+          media_description_options, session_options, data_codecs, sdes_policy,
+          GetCryptos(current_content), crypto_suites, RtpHeaderExtensions(),
+          ssrc_generator_, current_streams, data.get())) {
+    return false;
+  }
+
+  if (is_sctp) {
+    desc->AddContent(media_description_options.mid, MediaProtocolType::kSctp,
+                     data.release());
+  } else {
+    data->set_bandwidth(kDataMaxBandwidth);
+    SetMediaProtocol(secure_transport, data.get());
+    desc->AddContent(media_description_options.mid, MediaProtocolType::kRtp,
+                     media_description_options.stopped, data.release());
+  }
+  if (!AddTransportOffer(media_description_options.mid,
+                         media_description_options.transport_options,
+                         current_description, desc, ice_credentials)) {
+    return false;
+  }
+  return true;
 }
 
 // |audio_codecs| = set of all possible codecs that can be used, with correct
@@ -2335,15 +2287,9 @@
   // Do not require or create SDES cryptos if DTLS is used.
   cricket::SecurePolicy sdes_policy =
       audio_transport->secure() ? cricket::SEC_DISABLED : secure();
-  if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
-                         media_description_options, session_options,
-                         ssrc_generator_, current_streams,
-                         audio_answer.get())) {
-    return false;
-  }
   if (!CreateMediaContentAnswer(
           offer_audio_description, media_description_options, session_options,
-          sdes_policy, GetCryptos(current_content),
+          filtered_codecs, sdes_policy, GetCryptos(current_content),
           audio_rtp_header_extensions(), ssrc_generator_,
           enable_encrypted_rtp_header_extensions_, current_streams,
           bundle_enabled, audio_answer.get())) {
@@ -2430,15 +2376,9 @@
   // Do not require or create SDES cryptos if DTLS is used.
   cricket::SecurePolicy sdes_policy =
       video_transport->secure() ? cricket::SEC_DISABLED : secure();
-  if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
-                         media_description_options, session_options,
-                         ssrc_generator_, current_streams,
-                         video_answer.get())) {
-    return false;
-  }
   if (!CreateMediaContentAnswer(
           offer_video_description, media_description_options, session_options,
-          sdes_policy, GetCryptos(current_content),
+          filtered_codecs, sdes_policy, GetCryptos(current_content),
           video_rtp_header_extensions(), ssrc_generator_,
           enable_encrypted_rtp_header_extensions_, current_streams,
           bundle_enabled, video_answer.get())) {
@@ -2486,52 +2426,29 @@
     return false;
   }
 
+  std::unique_ptr<DataContentDescription> data_answer(
+      new DataContentDescription());
   // Do not require or create SDES cryptos if DTLS is used.
   cricket::SecurePolicy sdes_policy =
       data_transport->secure() ? cricket::SEC_DISABLED : secure();
   bool bundle_enabled = offer_description->HasGroup(GROUP_TYPE_BUNDLE) &&
                         session_options.bundle_enabled;
   RTC_CHECK(IsMediaContentOfType(offer_content, MEDIA_TYPE_DATA));
-  std::unique_ptr<MediaContentDescription> data_answer;
-  if (offer_content->media_description()->as_sctp()) {
-    // SCTP data content
-    data_answer = absl::make_unique<SctpDataContentDescription>();
-    const SctpDataContentDescription* offer_data_description =
-        offer_content->media_description()->as_sctp();
-    // Respond with the offerer's proto, whatever it is.
-    data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
-    if (!CreateMediaContentAnswer(
-            offer_data_description, media_description_options, session_options,
-            sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
-            ssrc_generator_, enable_encrypted_rtp_header_extensions_,
-            current_streams, bundle_enabled, data_answer.get())) {
-      return false;  // Fails the session setup.
-    }
-    // Respond with sctpmap if the offer uses sctpmap.
-    bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
-    data_answer->as_sctp()->set_use_sctpmap(offer_uses_sctpmap);
-  } else {
-    // RTP offer
-    data_answer = absl::make_unique<DataContentDescription>();
-
-    RTC_CHECK(offer_content->media_description()->as_data());
-    const DataContentDescription* offer_data_description =
-        offer_content->media_description()->as_data();
-    if (!SetCodecsInAnswer(offer_data_description, data_codecs,
-                           media_description_options, session_options,
-                           ssrc_generator_, current_streams,
-                           data_answer->as_data())) {
-      return false;
-    }
-    if (!CreateMediaContentAnswer(
-            offer_data_description, media_description_options, session_options,
-            sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
-            ssrc_generator_, enable_encrypted_rtp_header_extensions_,
-            current_streams, bundle_enabled, data_answer.get())) {
-      return false;  // Fails the session setup.
-    }
+  const DataContentDescription* offer_data_description =
+      offer_content->media_description()->as_data();
+  if (!CreateMediaContentAnswer(
+          offer_data_description, media_description_options, session_options,
+          data_codecs, sdes_policy, GetCryptos(current_content),
+          RtpHeaderExtensions(), ssrc_generator_,
+          enable_encrypted_rtp_header_extensions_, current_streams,
+          bundle_enabled, data_answer.get())) {
+    return false;  // Fails the session setup.
   }
 
+  // Respond with sctpmap if the offer uses sctpmap.
+  bool offer_uses_sctpmap = offer_data_description->use_sctpmap();
+  data_answer->set_use_sctpmap(offer_uses_sctpmap);
+
   bool secure = bundle_transport ? bundle_transport->description.secure()
                                  : data_transport->secure();
 
@@ -2654,26 +2571,20 @@
 
 const AudioContentDescription* GetFirstAudioContentDescription(
     const SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
-  return desc ? desc->as_audio() : nullptr;
+  return static_cast<const AudioContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
 }
 
 const VideoContentDescription* GetFirstVideoContentDescription(
     const SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
-  return desc ? desc->as_video() : nullptr;
+  return static_cast<const VideoContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
 }
 
 const DataContentDescription* GetFirstDataContentDescription(
     const SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
-  return desc ? desc->as_data() : nullptr;
-}
-
-const SctpDataContentDescription* GetFirstSctpDataContentDescription(
-    const SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
-  return desc ? desc->as_sctp() : nullptr;
+  return static_cast<const DataContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
 }
 
 //
@@ -2732,26 +2643,20 @@
 
 AudioContentDescription* GetFirstAudioContentDescription(
     SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO);
-  return desc ? desc->as_audio() : nullptr;
+  return static_cast<AudioContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
 }
 
 VideoContentDescription* GetFirstVideoContentDescription(
     SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO);
-  return desc ? desc->as_video() : nullptr;
+  return static_cast<VideoContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
 }
 
 DataContentDescription* GetFirstDataContentDescription(
     SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
-  return desc ? desc->as_data() : nullptr;
-}
-
-SctpDataContentDescription* GetFirstSctpDataContentDescription(
-    SessionDescription* sdesc) {
-  auto desc = GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA);
-  return desc ? desc->as_sctp() : nullptr;
+  return static_cast<DataContentDescription*>(
+      GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
 }
 
 }  // namespace cricket
diff --git a/pc/media_session.h b/pc/media_session.h
index 112508e..33c8c17 100644
--- a/pc/media_session.h
+++ b/pc/media_session.h
@@ -24,7 +24,6 @@
 #include "p2p/base/ice_credentials_iterator.h"
 #include "p2p/base/transport_description_factory.h"
 #include "pc/jsep_transport.h"
-#include "pc/media_protocol_names.h"
 #include "pc/session_description.h"
 #include "rtc_base/unique_id_generator.h"
 
@@ -240,23 +239,6 @@
       SessionDescription* desc,
       IceCredentialsIterator* ice_credentials) const;
 
-  bool AddSctpDataContentForOffer(
-      const MediaDescriptionOptions& media_description_options,
-      const MediaSessionOptions& session_options,
-      const ContentInfo* current_content,
-      const SessionDescription* current_description,
-      StreamParamsVec* current_streams,
-      SessionDescription* desc,
-      IceCredentialsIterator* ice_credentials) const;
-  bool AddRtpDataContentForOffer(
-      const MediaDescriptionOptions& media_description_options,
-      const MediaSessionOptions& session_options,
-      const ContentInfo* current_content,
-      const SessionDescription* current_description,
-      const DataCodecs& data_codecs,
-      StreamParamsVec* current_streams,
-      SessionDescription* desc,
-      IceCredentialsIterator* ice_credentials) const;
   bool AddDataContentForOffer(
       const MediaDescriptionOptions& media_description_options,
       const MediaSessionOptions& session_options,
@@ -349,8 +331,6 @@
     const SessionDescription* sdesc);
 const DataContentDescription* GetFirstDataContentDescription(
     const SessionDescription* sdesc);
-const SctpDataContentDescription* GetFirstSctpDataContentDescription(
-    const SessionDescription* sdesc);
 // Non-const versions of the above functions.
 // Useful when modifying an existing description.
 ContentInfo* GetFirstMediaContent(ContentInfos* contents, MediaType media_type);
@@ -368,8 +348,6 @@
     SessionDescription* sdesc);
 DataContentDescription* GetFirstDataContentDescription(
     SessionDescription* sdesc);
-SctpDataContentDescription* GetFirstSctpDataContentDescription(
-    SessionDescription* sdesc);
 
 // Helper functions to return crypto suites used for SDES.
 void GetSupportedAudioSdesCryptoSuites(
@@ -391,6 +369,9 @@
     const webrtc::CryptoOptions& crypto_options,
     std::vector<std::string>* crypto_suite_names);
 
+// Returns true if the given media section protocol indicates use of RTP.
+bool IsRtpProtocol(const std::string& protocol);
+
 }  // namespace cricket
 
 #endif  // PC_MEDIA_SESSION_H_
diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc
index bd01041..1136607 100644
--- a/pc/media_session_unittest.cc
+++ b/pc/media_session_unittest.cc
@@ -62,7 +62,6 @@
 using cricket::MediaType;
 using cricket::RidDescription;
 using cricket::RidDirection;
-using cricket::SctpDataContentDescription;
 using cricket::SEC_DISABLED;
 using cricket::SEC_ENABLED;
 using cricket::SEC_REQUIRED;
@@ -1337,16 +1336,15 @@
   ASSERT_TRUE(offer.get() != NULL);
   ContentInfo* dc_offer = offer->GetContentByName("data");
   ASSERT_TRUE(dc_offer != NULL);
-  SctpDataContentDescription* dcd_offer =
-      dc_offer->media_description()->as_sctp();
+  DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
   EXPECT_TRUE(dcd_offer->use_sctpmap());
 
   std::unique_ptr<SessionDescription> answer =
       f2_.CreateAnswer(offer.get(), opts, NULL);
   const ContentInfo* dc_answer = answer->GetContentByName("data");
   ASSERT_TRUE(dc_answer != NULL);
-  const SctpDataContentDescription* dcd_answer =
-      dc_answer->media_description()->as_sctp();
+  const DataContentDescription* dcd_answer =
+      dc_answer->media_description()->as_data();
   EXPECT_TRUE(dcd_answer->use_sctpmap());
 }
 
@@ -1358,16 +1356,15 @@
   ASSERT_TRUE(offer.get() != NULL);
   ContentInfo* dc_offer = offer->GetContentByName("data");
   ASSERT_TRUE(dc_offer != NULL);
-  SctpDataContentDescription* dcd_offer =
-      dc_offer->media_description()->as_sctp();
+  DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
   dcd_offer->set_use_sctpmap(false);
 
   std::unique_ptr<SessionDescription> answer =
       f2_.CreateAnswer(offer.get(), opts, NULL);
   const ContentInfo* dc_answer = answer->GetContentByName("data");
   ASSERT_TRUE(dc_answer != NULL);
-  const SctpDataContentDescription* dcd_answer =
-      dc_answer->media_description()->as_sctp();
+  const DataContentDescription* dcd_answer =
+      dc_answer->media_description()->as_data();
   EXPECT_FALSE(dcd_answer->use_sctpmap());
 }
 
@@ -1388,9 +1385,7 @@
   ASSERT_TRUE(offer.get() != nullptr);
   ContentInfo* dc_offer = offer->GetContentByName("data");
   ASSERT_TRUE(dc_offer != nullptr);
-  SctpDataContentDescription* dcd_offer =
-      dc_offer->media_description()->as_sctp();
-  ASSERT_TRUE(dcd_offer);
+  DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
 
   std::vector<std::string> protos = {"DTLS/SCTP", "UDP/DTLS/SCTP",
                                      "TCP/DTLS/SCTP"};
@@ -1400,8 +1395,8 @@
         f2_.CreateAnswer(offer.get(), opts, nullptr);
     const ContentInfo* dc_answer = answer->GetContentByName("data");
     ASSERT_TRUE(dc_answer != nullptr);
-    const SctpDataContentDescription* dcd_answer =
-        dc_answer->media_description()->as_sctp();
+    const DataContentDescription* dcd_answer =
+        dc_answer->media_description()->as_data();
     EXPECT_FALSE(dc_answer->rejected);
     EXPECT_EQ(proto, dcd_answer->protocol());
   }
@@ -1485,8 +1480,7 @@
   ASSERT_TRUE(dc_offer != NULL);
   DataContentDescription* dcd_offer = dc_offer->media_description()->as_data();
   ASSERT_TRUE(dcd_offer != NULL);
-  // Offer must be acceptable as an RTP protocol in order to be set.
-  std::string protocol = "RTP/a weird unknown protocol";
+  std::string protocol = "a weird unknown protocol";
   dcd_offer->set_protocol(protocol);
 
   std::unique_ptr<SessionDescription> answer =
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index bf3ad56..1b011a3 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -559,13 +559,24 @@
 // Get the SCTP port out of a SessionDescription.
 // Return -1 if not found.
 int GetSctpPort(const SessionDescription* session_description) {
-  const cricket::SctpDataContentDescription* data_desc =
-      GetFirstSctpDataContentDescription(session_description);
+  const cricket::DataContentDescription* data_desc =
+      GetFirstDataContentDescription(session_description);
   RTC_DCHECK(data_desc);
   if (!data_desc) {
     return -1;
   }
-  return data_desc->port();
+  std::string value;
+  cricket::DataCodec match_pattern(cricket::kGoogleSctpDataCodecPlType,
+                                   cricket::kGoogleSctpDataCodecName);
+  for (const cricket::DataCodec& codec : data_desc->codecs()) {
+    if (!codec.Matches(match_pattern)) {
+      continue;
+    }
+    if (codec.GetParam(cricket::kCodecParamPort, &value)) {
+      return rtc::FromString<int>(value);
+    }
+  }
+  return -1;
 }
 
 // Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
@@ -2413,9 +2424,8 @@
   if (data_content) {
     const cricket::DataContentDescription* data_desc =
         data_content->media_description()->as_data();
-    // data_desc will be null if this is an SCTP description.
-    if (data_desc && absl::StartsWith(data_desc->protocol(),
-                                      cricket::kMediaProtocolRtpPrefix)) {
+    if (absl::StartsWith(data_desc->protocol(),
+                         cricket::kMediaProtocolRtpPrefix)) {
       UpdateLocalRtpDataChannels(data_desc->streams());
     }
   }
diff --git a/pc/peer_connection_data_channel_unittest.cc b/pc/peer_connection_data_channel_unittest.cc
index 4080dd9..ad3817e 100644
--- a/pc/peer_connection_data_channel_unittest.cc
+++ b/pc/peer_connection_data_channel_unittest.cc
@@ -193,11 +193,14 @@
   // Changes the SCTP data channel port on the given session description.
   void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
                                    int port) {
+    cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
+                                  cricket::kGoogleSctpDataCodecName);
+    sctp_codec.SetParam(cricket::kCodecParamPort, port);
+
     auto* data_content = cricket::GetFirstDataContent(desc);
     RTC_DCHECK(data_content);
-    auto* data_desc = data_content->media_description()->as_sctp();
-    RTC_DCHECK(data_desc);
-    data_desc->set_port(port);
+    auto* data_desc = data_content->media_description()->as_data();
+    data_desc->set_codecs({sctp_codec});
   }
 
   std::unique_ptr<rtc::VirtualSocketServer> vss_;
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
index e84ffe0..6087f0f 100644
--- a/pc/peer_connection_integrationtest.cc
+++ b/pc/peer_connection_integrationtest.cc
@@ -3450,8 +3450,8 @@
 }
 
 static void MakeSpecCompliantSctpOffer(cricket::SessionDescription* desc) {
-  cricket::SctpDataContentDescription* dcd_offer =
-      GetFirstSctpDataContentDescription(desc);
+  cricket::DataContentDescription* dcd_offer =
+      GetFirstDataContentDescription(desc);
   ASSERT_TRUE(dcd_offer);
   dcd_offer->set_use_sctpmap(false);
   dcd_offer->set_protocol("UDP/DTLS/SCTP");
diff --git a/pc/session_description.h b/pc/session_description.h
index e5a7dfa..7b70ddf 100644
--- a/pc/session_description.h
+++ b/pc/session_description.h
@@ -26,7 +26,6 @@
 #include "media/base/stream_params.h"
 #include "p2p/base/transport_description.h"
 #include "p2p/base/transport_info.h"
-#include "pc/media_protocol_names.h"
 #include "pc/simulcast_description.h"
 #include "rtc_base/socket_address.h"
 
@@ -45,6 +44,12 @@
 
 extern const char kMediaProtocolDtlsSavpf[];
 
+extern const char kMediaProtocolRtpPrefix[];
+
+extern const char kMediaProtocolSctp[];
+extern const char kMediaProtocolDtlsSctp[];
+extern const char kMediaProtocolUdpDtlsSctp[];
+extern const char kMediaProtocolTcpDtlsSctp[];
 
 // Options to control how session descriptions are generated.
 const int kAutoBandwidth = -1;
@@ -52,7 +57,6 @@
 class AudioContentDescription;
 class DataContentDescription;
 class VideoContentDescription;
-class SctpDataContentDescription;
 
 // Describes a session description media section. There are subclasses for each
 // media type (audio, video, data) that will have additional information.
@@ -78,9 +82,6 @@
   virtual DataContentDescription* as_data() { return nullptr; }
   virtual const DataContentDescription* as_data() const { return nullptr; }
 
-  virtual SctpDataContentDescription* as_sctp() { return nullptr; }
-  virtual const SctpDataContentDescription* as_sctp() const { return nullptr; }
-
   virtual bool has_codecs() const = 0;
 
   virtual MediaContentDescription* Copy() const = 0;
@@ -88,9 +89,7 @@
   // |protocol| is the expected media transport protocol, such as RTP/AVPF,
   // RTP/SAVPF or SCTP/DTLS.
   std::string protocol() const { return protocol_; }
-  virtual void set_protocol(const std::string& protocol) {
-    protocol_ = protocol;
-  }
+  void set_protocol(const std::string& protocol) { protocol_ = protocol; }
 
   webrtc::RtpTransceiverDirection direction() const { return direction_; }
   void set_direction(webrtc::RtpTransceiverDirection direction) {
@@ -248,17 +247,12 @@
 template <class C>
 class MediaContentDescriptionImpl : public MediaContentDescription {
  public:
-  void set_protocol(const std::string& protocol) override {
-    RTC_DCHECK(IsRtpProtocol(protocol));
-    protocol_ = protocol;
-  }
-
   typedef C CodecType;
 
   // Codecs should be in preference order (most preferred codec first).
   const std::vector<C>& codecs() const { return codecs_; }
   void set_codecs(const std::vector<C>& codecs) { codecs_ = codecs; }
-  bool has_codecs() const override { return !codecs_.empty(); }
+  virtual bool has_codecs() const { return !codecs_.empty(); }
   bool HasCodec(int id) {
     bool found = false;
     for (typename std::vector<C>::iterator iter = codecs_.begin();
@@ -324,37 +318,12 @@
   virtual MediaType type() const { return MEDIA_TYPE_DATA; }
   virtual DataContentDescription* as_data() { return this; }
   virtual const DataContentDescription* as_data() const { return this; }
-};
-
-class SctpDataContentDescription : public MediaContentDescription {
- public:
-  SctpDataContentDescription() {}
-  SctpDataContentDescription* Copy() const override {
-    return new SctpDataContentDescription(*this);
-  }
-  MediaType type() const override { return MEDIA_TYPE_DATA; }
-  SctpDataContentDescription* as_sctp() override { return this; }
-  const SctpDataContentDescription* as_sctp() const override { return this; }
-  bool has_codecs() const override { return false; }
-  void set_protocol(const std::string& protocol) override {
-    RTC_DCHECK(IsSctpProtocol(protocol));
-    protocol_ = protocol;
-  }
 
   bool use_sctpmap() const { return use_sctpmap_; }
   void set_use_sctpmap(bool enable) { use_sctpmap_ = enable; }
-  int port() const { return port_; }
-  void set_port(int port) { port_ = port; }
-  int max_message_size() const { return max_message_size_; }
-  void set_max_message_size(int max_message_size) {
-    max_message_size_ = max_message_size;
-  }
 
  private:
-  bool use_sctpmap_ = true;  // Note: "true" is no longer conformant.
-  // Defaults should be constants imported from SCTP. Quick hack.
-  int port_ = 5000;
-  int max_message_size_ = 256 * 1024;
+  bool use_sctpmap_ = true;
 };
 
 // Protocol used for encoding media. This is the "top level" protocol that may
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 7c65f87..984a1e1 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -54,30 +54,29 @@
 using cricket::ContentInfo;
 using cricket::CryptoParams;
 using cricket::DataContentDescription;
-using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
 using cricket::ICE_CANDIDATE_COMPONENT_RTP;
-using cricket::kCodecParamAssociatedPayloadType;
-using cricket::kCodecParamMaxAverageBitrate;
+using cricket::ICE_CANDIDATE_COMPONENT_RTCP;
 using cricket::kCodecParamMaxBitrate;
-using cricket::kCodecParamMaxPlaybackRate;
 using cricket::kCodecParamMaxPTime;
 using cricket::kCodecParamMaxQuantization;
 using cricket::kCodecParamMinBitrate;
 using cricket::kCodecParamMinPTime;
 using cricket::kCodecParamPTime;
-using cricket::kCodecParamSctpProtocol;
-using cricket::kCodecParamSctpStreams;
 using cricket::kCodecParamSPropStereo;
 using cricket::kCodecParamStartBitrate;
 using cricket::kCodecParamStereo;
-using cricket::kCodecParamUseDtx;
 using cricket::kCodecParamUseInbandFec;
+using cricket::kCodecParamUseDtx;
+using cricket::kCodecParamSctpProtocol;
+using cricket::kCodecParamSctpStreams;
+using cricket::kCodecParamMaxAverageBitrate;
+using cricket::kCodecParamMaxPlaybackRate;
+using cricket::kCodecParamAssociatedPayloadType;
 using cricket::MediaContentDescription;
-using cricket::MediaProtocolType;
 using cricket::MediaType;
-using cricket::RidDescription;
 using cricket::RtpHeaderExtensions;
-using cricket::SctpDataContentDescription;
+using cricket::MediaProtocolType;
+using cricket::RidDescription;
 using cricket::SimulcastDescription;
 using cricket::SimulcastLayer;
 using cricket::SimulcastLayerList;
@@ -1338,6 +1337,8 @@
   const MediaContentDescription* media_desc = content_info->media_description();
   RTC_DCHECK(media_desc);
 
+  int sctp_port = cricket::kSctpDefaultPort;
+
   // RFC 4566
   // m=<media> <port> <proto> <fmt>
   // fmt is a list of payload type numbers that MAY be used in the session.
@@ -1365,18 +1366,24 @@
       fmt.append(rtc::ToString(codec.id));
     }
   } else if (media_type == cricket::MEDIA_TYPE_DATA) {
+    const DataContentDescription* data_desc = media_desc->as_data();
     if (IsDtlsSctp(media_desc->protocol())) {
-      const cricket::SctpDataContentDescription* data_desc =
-          media_desc->as_sctp();
       fmt.append(" ");
 
       if (data_desc->use_sctpmap()) {
-        fmt.append(rtc::ToString(data_desc->port()));
+        for (const cricket::DataCodec& codec : data_desc->codecs()) {
+          if (absl::EqualsIgnoreCase(codec.name,
+                                     cricket::kGoogleSctpDataCodecName) &&
+              codec.GetParam(cricket::kCodecParamPort, &sctp_port)) {
+            break;
+          }
+        }
+
+        fmt.append(rtc::ToString(sctp_port));
       } else {
         fmt.append(kDefaultSctpmapProtocol);
       }
     } else {
-      const DataContentDescription* data_desc = media_desc->as_data();
       for (const cricket::DataCodec& codec : data_desc->codecs()) {
         fmt.append(" ");
         fmt.append(rtc::ToString(codec.id));
@@ -1516,10 +1523,9 @@
   AddLine(os.str(), message);
 
   if (IsDtlsSctp(media_desc->protocol())) {
-    const cricket::SctpDataContentDescription* data_desc =
-        media_desc->as_sctp();
+    const DataContentDescription* data_desc = media_desc->as_data();
     bool use_sctpmap = data_desc->use_sctpmap();
-    BuildSctpContentAttributes(message, data_desc->port(), use_sctpmap);
+    BuildSctpContentAttributes(message, sctp_port, use_sctpmap);
   } else if (IsRtp(media_desc->protocol())) {
     BuildRtpContentAttributes(media_desc, media_type, msid_signaling, message);
   }
@@ -1828,6 +1834,43 @@
   }
 }
 
+cricket::DataCodec FindOrMakeSctpDataCodec(DataContentDescription* media_desc) {
+  for (const auto& codec : media_desc->codecs()) {
+    if (absl::EqualsIgnoreCase(codec.name, cricket::kGoogleSctpDataCodecName)) {
+      return codec;
+    }
+  }
+  cricket::DataCodec codec_port(cricket::kGoogleSctpDataCodecPlType,
+                                cricket::kGoogleSctpDataCodecName);
+  return codec_port;
+}
+
+bool AddOrModifySctpDataCodecPort(DataContentDescription* media_desc,
+                                  int sctp_port) {
+  // Add the SCTP Port number as a pseudo-codec "port" parameter
+  auto codec = FindOrMakeSctpDataCodec(media_desc);
+  int dummy;
+  if (codec.GetParam(cricket::kCodecParamPort, &dummy)) {
+    return false;
+  }
+  codec.SetParam(cricket::kCodecParamPort, sctp_port);
+  media_desc->AddOrReplaceCodec(codec);
+  return true;
+}
+
+bool AddOrModifySctpDataMaxMessageSize(DataContentDescription* media_desc,
+                                       int max_message_size) {
+  // Add the SCTP Max Message Size as a pseudo-parameter to the codec
+  auto codec = FindOrMakeSctpDataCodec(media_desc);
+  int dummy;
+  if (codec.GetParam(cricket::kCodecParamMaxMessageSize, &dummy)) {
+    return false;
+  }
+  codec.SetParam(cricket::kCodecParamMaxMessageSize, max_message_size);
+  media_desc->AddOrReplaceCodec(codec);
+  return true;
+}
+
 bool GetMinValue(const std::vector<int>& values, int* value) {
   if (values.empty()) {
     return false;
@@ -2705,30 +2748,24 @@
           payload_types, pos, &content_name, &bundle_only,
           &section_msid_signaling, &transport, candidates, error);
     } else if (HasAttribute(line, kMediaTypeData)) {
-      if (IsDtlsSctp(protocol)) {
-        auto data_desc = absl::make_unique<SctpDataContentDescription>();
+      std::unique_ptr<DataContentDescription> data_desc =
+          ParseContentDescription<DataContentDescription>(
+              message, cricket::MEDIA_TYPE_DATA, mline_index, protocol,
+              payload_types, pos, &content_name, &bundle_only,
+              &section_msid_signaling, &transport, candidates, error);
+
+      if (data_desc && IsDtlsSctp(protocol)) {
         int p;
         if (rtc::FromString(fields[3], &p)) {
-          data_desc->set_port(p);
+          if (!AddOrModifySctpDataCodecPort(data_desc.get(), p)) {
+            return false;
+          }
         } else if (fields[3] == kDefaultSctpmapProtocol) {
           data_desc->set_use_sctpmap(false);
         }
-        if (!ParseContent(message, cricket::MEDIA_TYPE_DATA, mline_index,
-                          protocol, payload_types, pos, &content_name,
-                          &bundle_only, &section_msid_signaling,
-                          data_desc.get(), &transport, candidates, error)) {
-          return false;
-        }
-        content = std::move(data_desc);
-      } else {
-        // RTP
-        std::unique_ptr<DataContentDescription> data_desc =
-            ParseContentDescription<DataContentDescription>(
-                message, cricket::MEDIA_TYPE_DATA, mline_index, protocol,
-                payload_types, pos, &content_name, &bundle_only,
-                &section_msid_signaling, &transport, candidates, error);
-        content = std::move(data_desc);
       }
+
+      content = std::move(data_desc);
     } else {
       RTC_LOG(LS_WARNING) << "Unsupported media type: " << line;
       continue;
@@ -3101,15 +3138,13 @@
             line, "sctp-port attribute found in non-data media description.",
             error);
       }
-      if (media_desc->as_sctp()->use_sctpmap()) {
-        return ParseFailed(
-            line, "sctp-port attribute can't be used with sctpmap.", error);
-      }
       int sctp_port;
       if (!ParseSctpPort(line, &sctp_port, error)) {
         return false;
       }
-      media_desc->as_sctp()->set_port(sctp_port);
+      if (!AddOrModifySctpDataCodecPort(media_desc->as_data(), sctp_port)) {
+        return false;
+      }
     } else if (IsDtlsSctp(protocol) &&
                HasAttribute(line, kAttributeMaxMessageSize)) {
       if (media_type != cricket::MEDIA_TYPE_DATA) {
@@ -3122,7 +3157,10 @@
       if (!ParseSctpMaxMessageSize(line, &max_message_size, error)) {
         return false;
       }
-      media_desc->as_sctp()->set_max_message_size(max_message_size);
+      if (!AddOrModifySctpDataMaxMessageSize(media_desc->as_data(),
+                                             max_message_size)) {
+        return false;
+      }
     } else if (IsRtp(protocol)) {
       //
       // RTP specific attrubtes
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
index 78fc8e0..3de2b60 100644
--- a/pc/webrtc_sdp_unittest.cc
+++ b/pc/webrtc_sdp_unittest.cc
@@ -65,7 +65,6 @@
 using cricket::RELAY_PORT_TYPE;
 using cricket::RidDescription;
 using cricket::RidDirection;
-using cricket::SctpDataContentDescription;
 using cricket::SessionDescription;
 using cricket::SimulcastDescription;
 using cricket::SimulcastLayer;
@@ -1446,15 +1445,8 @@
 
   void CompareDataContentDescription(const DataContentDescription* dcd1,
                                      const DataContentDescription* dcd2) {
-    CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
-  }
-
-  void CompareSctpDataContentDescription(
-      const SctpDataContentDescription* dcd1,
-      const SctpDataContentDescription* dcd2) {
     EXPECT_EQ(dcd1->use_sctpmap(), dcd2->use_sctpmap());
-    EXPECT_EQ(dcd1->port(), dcd2->port());
-    EXPECT_EQ(dcd1->max_message_size(), dcd2->max_message_size());
+    CompareMediaContentDescription<DataContentDescription>(dcd1, dcd2);
   }
 
   void CompareSessionDescription(const SessionDescription& desc1,
@@ -1492,21 +1484,10 @@
       }
 
       ASSERT_EQ(IsDataContent(&c1), IsDataContent(&c2));
-      if (c1.media_description()->as_sctp()) {
-        ASSERT_TRUE(c2.media_description()->as_sctp());
-        const SctpDataContentDescription* scd1 =
-            c1.media_description()->as_sctp();
-        const SctpDataContentDescription* scd2 =
-            c2.media_description()->as_sctp();
-        CompareSctpDataContentDescription(scd1, scd2);
-      } else {
-        if (IsDataContent(&c1)) {
-          const DataContentDescription* dcd1 =
-              c1.media_description()->as_data();
-          const DataContentDescription* dcd2 =
-              c2.media_description()->as_data();
-          CompareDataContentDescription(dcd1, dcd2);
-        }
+      if (IsDataContent(&c1)) {
+        const DataContentDescription* dcd1 = c1.media_description()->as_data();
+        const DataContentDescription* dcd2 = c2.media_description()->as_data();
+        CompareDataContentDescription(dcd1, dcd2);
       }
 
       CompareSimulcastDescription(
@@ -1779,12 +1760,14 @@
   }
 
   void AddSctpDataChannel(bool use_sctpmap) {
-    std::unique_ptr<SctpDataContentDescription> data(
-        new SctpDataContentDescription());
-    sctp_desc_ = data.get();
-    sctp_desc_->set_use_sctpmap(use_sctpmap);
-    sctp_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
-    sctp_desc_->set_port(kDefaultSctpPort);
+    std::unique_ptr<DataContentDescription> data(new DataContentDescription());
+    data_desc_ = data.get();
+    data_desc_->set_use_sctpmap(use_sctpmap);
+    data_desc_->set_protocol(cricket::kMediaProtocolDtlsSctp);
+    DataCodec codec(cricket::kGoogleSctpDataCodecPlType,
+                    cricket::kGoogleSctpDataCodecName);
+    codec.SetParam(cricket::kCodecParamPort, kDefaultSctpPort);
+    data_desc_->AddCodec(codec);
     desc_.AddContent(kDataContentName, MediaProtocolType::kSctp,
                      data.release());
     desc_.AddTransportInfo(TransportInfo(
@@ -2061,7 +2044,6 @@
   AudioContentDescription* audio_desc_;
   VideoContentDescription* video_desc_;
   DataContentDescription* data_desc_;
-  SctpDataContentDescription* sctp_desc_;
   Candidates candidates_;
   std::unique_ptr<IceCandidateInterface> jcandidate_;
   JsepSessionDescription jdesc_;
@@ -2233,26 +2215,21 @@
   EXPECT_EQ(message, expected_sdp);
 }
 
-void MutateJsepSctpPort(JsepSessionDescription* jdesc,
-                        const SessionDescription& desc,
-                        int port) {
-  // Take our pre-built session description and change the SCTP port.
-  cricket::SessionDescription* mutant = desc.Copy();
-  SctpDataContentDescription* dcdesc =
-      mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
-  dcdesc->set_port(port);
-  // Note: mutant's owned by jdesc now.
-  ASSERT_TRUE(jdesc->Initialize(mutant, kSessionId, kSessionVersion));
-}
-
 TEST_F(WebRtcSdpTest, SerializeWithSctpDataChannelAndNewPort) {
   bool use_sctpmap = true;
   AddSctpDataChannel(use_sctpmap);
   JsepSessionDescription jsep_desc(kDummyType);
   MakeDescriptionWithoutCandidates(&jsep_desc);
+  DataContentDescription* dcdesc =
+      jsep_desc.description()
+          ->GetContentDescriptionByName(kDataContentName)
+          ->as_data();
 
   const int kNewPort = 1234;
-  MutateJsepSctpPort(&jsep_desc, desc_, kNewPort);
+  cricket::DataCodec codec(cricket::kGoogleSctpDataCodecPlType,
+                           cricket::kGoogleSctpDataCodecName);
+  codec.SetParam(cricket::kCodecParamPort, kNewPort);
+  dcdesc->AddOrReplaceCodec(codec);
 
   std::string message = webrtc::SdpSerialize(jsep_desc);
 
@@ -2891,12 +2868,14 @@
 // Helper function to set the max-message-size parameter in the
 // SCTP data codec.
 void MutateJsepSctpMaxMessageSize(const SessionDescription& desc,
-                                  int new_value,
+                                  const std::string& new_value,
                                   JsepSessionDescription* jdesc) {
   cricket::SessionDescription* mutant = desc.Copy();
-  SctpDataContentDescription* dcdesc =
-      mutant->GetContentDescriptionByName(kDataContentName)->as_sctp();
-  dcdesc->set_max_message_size(new_value);
+  DataContentDescription* dcdesc =
+      mutant->GetContentDescriptionByName(kDataContentName)->as_data();
+  std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
+  codecs[0].SetParam(cricket::kCodecParamMaxMessageSize, new_value);
+  dcdesc->set_codecs(codecs);
   jdesc->Initialize(mutant, kSessionId, kSessionVersion);
 }
 
@@ -2908,7 +2887,7 @@
 
   sdp_with_data.append(kSdpSctpDataChannelStringWithSctpColonPort);
   sdp_with_data.append("a=max-message-size:12345\r\n");
-  MutateJsepSctpMaxMessageSize(desc_, 12345, &jdesc);
+  MutateJsepSctpMaxMessageSize(desc_, "12345", &jdesc);
   JsepSessionDescription jdesc_output(kDummyType);
 
   // Verify with DTLS/SCTP.
@@ -2958,13 +2937,29 @@
   // No crash is a pass.
 }
 
+void MutateJsepSctpPort(JsepSessionDescription* jdesc,
+                        const SessionDescription& desc) {
+  // take our pre-built session description and change the SCTP port.
+  std::unique_ptr<cricket::SessionDescription> mutant = desc.Clone();
+  DataContentDescription* dcdesc =
+      mutant->GetContentDescriptionByName(kDataContentName)->as_data();
+  std::vector<cricket::DataCodec> codecs(dcdesc->codecs());
+  EXPECT_EQ(1U, codecs.size());
+  EXPECT_EQ(cricket::kGoogleSctpDataCodecPlType, codecs[0].id);
+  codecs[0].SetParam(cricket::kCodecParamPort, kUnusualSctpPort);
+  dcdesc->set_codecs(codecs);
+
+  ASSERT_TRUE(
+      jdesc->Initialize(std::move(mutant), kSessionId, kSessionVersion));
+}
+
 TEST_F(WebRtcSdpTest, DeserializeSdpWithSctpDataChannelAndUnusualPort) {
   bool use_sctpmap = true;
   AddSctpDataChannel(use_sctpmap);
 
   // First setup the expected JsepSessionDescription.
   JsepSessionDescription jdesc(kDummyType);
-  MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
+  MutateJsepSctpPort(&jdesc, desc_);
 
   // Then get the deserialized JsepSessionDescription.
   std::string sdp_with_data = kSdpString;
@@ -2984,7 +2979,7 @@
   AddSctpDataChannel(use_sctpmap);
 
   JsepSessionDescription jdesc(kDummyType);
-  MutateJsepSctpPort(&jdesc, desc_, kUnusualSctpPort);
+  MutateJsepSctpPort(&jdesc, desc_);
 
   // We need to test the deserialized JsepSessionDescription from
   // kSdpSctpDataChannelStringWithSctpPort for
@@ -3020,7 +3015,7 @@
   bool use_sctpmap = true;
   AddSctpDataChannel(use_sctpmap);
   JsepSessionDescription jdesc(kDummyType);
-  SctpDataContentDescription* dcd = GetFirstSctpDataContentDescription(&desc_);
+  DataContentDescription* dcd = GetFirstDataContentDescription(&desc_);
   dcd->set_bandwidth(100 * 1000);
   ASSERT_TRUE(jdesc.Initialize(desc_.Clone(), kSessionId, kSessionVersion));