Replace MediaContentDirection with RtpTransceiverDirection

Bug: webrtc:8558
Change-Id: I410d17cce235e0b42038cf0b125fd916010f50ae
Reviewed-on: https://webrtc-review.googlesource.com/24745
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20922}
diff --git a/ortc/rtptransportcontrolleradapter.cc b/ortc/rtptransportcontrolleradapter.cc
index 9b2b69d..4e1ac1b 100644
--- a/ortc/rtptransportcontrolleradapter.cc
+++ b/ortc/rtptransportcontrolleradapter.cc
@@ -315,21 +315,18 @@
     }
   }
 
-  auto local_direction =
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(
-          local_audio_description_.direction());
-  bool local_send = RtpTransceiverDirectionHasSend(local_direction);
-  bool local_recv = RtpTransceiverDirectionHasRecv(local_direction);
+  bool local_send = false;
   int bandwidth = cricket::kAutoBandwidth;
   if (parameters.encodings.size() == 1u) {
     if (parameters.encodings[0].max_bitrate_bps) {
       bandwidth = *parameters.encodings[0].max_bitrate_bps;
     }
     local_send = parameters.encodings[0].active;
-  } else {
-    local_send = false;
   }
-  local_direction = RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
+  const bool local_recv =
+      RtpTransceiverDirectionHasRecv(local_audio_description_.direction());
+  const auto local_direction =
+      RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
   if (primary_ssrc && !stream_params_result.value().empty()) {
     *primary_ssrc = stream_params_result.value()[0].first_ssrc();
   }
@@ -350,12 +347,9 @@
   remote_audio_description_.set_bandwidth(bandwidth);
   local_audio_description_.mutable_streams() = stream_params_result.MoveValue();
   // Direction set based on encoding "active" flag.
-  local_audio_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          local_direction));
+  local_audio_description_.set_direction(local_direction);
   remote_audio_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          RtpTransceiverDirectionReversed(local_direction)));
+      RtpTransceiverDirectionReversed(local_direction));
 
   // Set remote content first, to ensure the stream is created with the correct
   // codec.
@@ -409,21 +403,18 @@
     }
   }
 
-  auto local_direction =
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(
-          local_audio_description_.direction());
-  bool local_send = RtpTransceiverDirectionHasSend(local_direction);
-  bool local_recv = RtpTransceiverDirectionHasRecv(local_direction);
+  bool local_send = false;
   int bandwidth = cricket::kAutoBandwidth;
   if (parameters.encodings.size() == 1u) {
     if (parameters.encodings[0].max_bitrate_bps) {
       bandwidth = *parameters.encodings[0].max_bitrate_bps;
     }
     local_send = parameters.encodings[0].active;
-  } else {
-    local_send = false;
   }
-  local_direction = RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
+  const bool local_recv =
+      RtpTransceiverDirectionHasRecv(local_audio_description_.direction());
+  const auto local_direction =
+      RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
   if (primary_ssrc && !stream_params_result.value().empty()) {
     *primary_ssrc = stream_params_result.value()[0].first_ssrc();
   }
@@ -444,12 +435,9 @@
   remote_video_description_.set_bandwidth(bandwidth);
   local_video_description_.mutable_streams() = stream_params_result.MoveValue();
   // Direction set based on encoding "active" flag.
-  local_video_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          local_direction));
+  local_video_description_.set_direction(local_direction);
   remote_video_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          RtpTransceiverDirectionReversed(local_direction)));
+      RtpTransceiverDirectionReversed(local_direction));
 
   // Set remote content first, to ensure the stream is created with the correct
   // codec.
@@ -500,12 +488,11 @@
     }
   }
 
-  bool local_send = RtpTransceiverDirectionHasSend(
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(
-          local_audio_description_.direction()));
-  bool local_recv =
+  const bool local_send =
+      RtpTransceiverDirectionHasSend(local_audio_description_.direction());
+  const bool local_recv =
       !parameters.encodings.empty() && parameters.encodings[0].active;
-  auto local_direction =
+  const auto local_direction =
       RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
 
   // Validation is done, so we can attempt applying the descriptions. Received
@@ -524,12 +511,9 @@
   remote_audio_description_.mutable_streams() =
       stream_params_result.MoveValue();
   // Direction set based on encoding "active" flag.
-  local_audio_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          local_direction));
+  local_audio_description_.set_direction(local_direction);
   remote_audio_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          RtpTransceiverDirectionReversed(local_direction)));
+      RtpTransceiverDirectionReversed(local_direction));
 
   if (!voice_channel_->SetLocalContent(&local_audio_description_,
                                        cricket::CA_OFFER, nullptr)) {
@@ -579,12 +563,11 @@
     }
   }
 
-  bool local_send = RtpTransceiverDirectionHasSend(
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(
-          local_video_description_.direction()));
-  bool local_recv =
+  const bool local_send =
+      RtpTransceiverDirectionHasSend(local_video_description_.direction());
+  const bool local_recv =
       !parameters.encodings.empty() && parameters.encodings[0].active;
-  auto local_direction =
+  const auto local_direction =
       RtpTransceiverDirectionFromSendRecv(local_send, local_recv);
 
   // Validation is done, so we can attempt applying the descriptions. Received
@@ -604,12 +587,9 @@
   remote_video_description_.mutable_streams() =
       stream_params_result.MoveValue();
   // Direction set based on encoding "active" flag.
-  local_video_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          local_direction));
+  local_video_description_.set_direction(local_direction);
   remote_video_description_.set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          RtpTransceiverDirectionReversed(local_direction)));
+      RtpTransceiverDirectionReversed(local_direction));
 
   if (!video_channel_->SetLocalContent(&local_video_description_,
                                        cricket::CA_OFFER, nullptr)) {
diff --git a/pc/channel.cc b/pc/channel.cc
index 8bb37d1..b976cc0 100644
--- a/pc/channel.cc
+++ b/pc/channel.cc
@@ -31,6 +31,7 @@
 #include "media/engine/webrtcvoiceengine.h"  // nogncheck
 #include "p2p/base/packettransportinternal.h"
 #include "pc/channelmanager.h"
+#include "pc/rtpmediautils.h"
 #include "pc/rtptransport.h"
 #include "pc/srtptransport.h"
 
@@ -103,14 +104,6 @@
   return packet && IsValidRtpRtcpPacketSize(rtcp, packet->size());
 }
 
-static bool IsReceiveContentDirection(MediaContentDirection direction) {
-  return direction == MD_SENDRECV || direction == MD_RECVONLY;
-}
-
-static bool IsSendContentDirection(MediaContentDirection direction) {
-  return direction == MD_SENDRECV || direction == MD_SENDONLY;
-}
-
 template <class Codec>
 void RtpParametersFromMediaDescription(
     const MediaContentDescriptionImpl<Codec>* desc,
@@ -510,7 +503,8 @@
 
 bool BaseChannel::IsReadyToReceiveMedia_w() const {
   // Receive data if we are enabled and have local content,
-  return enabled() && IsReceiveContentDirection(local_content_direction_);
+  return enabled() &&
+         webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_);
 }
 
 bool BaseChannel::IsReadyToSendMedia_w() const {
@@ -522,8 +516,9 @@
 bool BaseChannel::IsReadyToSendMedia_n() const {
   // Send outgoing data if we are enabled, have local and remote content,
   // and we have had some form of connectivity.
-  return enabled() && IsReceiveContentDirection(remote_content_direction_) &&
-         IsSendContentDirection(local_content_direction_) &&
+  return enabled() &&
+         webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
+         webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
          was_ever_writable() && (srtp_active() || !ShouldSetupDtlsSrtp_n());
 }
 
diff --git a/pc/channel.h b/pc/channel.h
index 00a57da..dbc6367 100644
--- a/pc/channel.h
+++ b/pc/channel.h
@@ -205,10 +205,10 @@
                       rtc::PacketTransportInternal* new_packet_transport);
 
   bool was_ever_writable() const { return was_ever_writable_; }
-  void set_local_content_direction(MediaContentDirection direction) {
+  void set_local_content_direction(webrtc::RtpTransceiverDirection direction) {
     local_content_direction_ = direction;
   }
-  void set_remote_content_direction(MediaContentDirection direction) {
+  void set_remote_content_direction(webrtc::RtpTransceiverDirection direction) {
     remote_content_direction_ = direction;
   }
   // These methods verify that:
@@ -413,8 +413,10 @@
   bool enabled_ = false;
   std::vector<StreamParams> local_streams_;
   std::vector<StreamParams> remote_streams_;
-  MediaContentDirection local_content_direction_ = MD_INACTIVE;
-  MediaContentDirection remote_content_direction_ = MD_INACTIVE;
+  webrtc::RtpTransceiverDirection local_content_direction_ =
+      webrtc::RtpTransceiverDirection::kInactive;
+  webrtc::RtpTransceiverDirection remote_content_direction_ =
+      webrtc::RtpTransceiverDirection::kInactive;
 
   // The cached encrypted header extension IDs.
   rtc::Optional<std::vector<int>> catched_send_extension_ids_;
diff --git a/pc/channel_unittest.cc b/pc/channel_unittest.cc
index 1813564..d1ceac5 100644
--- a/pc/channel_unittest.cc
+++ b/pc/channel_unittest.cc
@@ -33,6 +33,7 @@
 using cricket::DtlsTransportInternal;
 using cricket::FakeVoiceMediaChannel;
 using cricket::StreamParams;
+using webrtc::RtpTransceiverDirection;
 
 namespace {
 const cricket::AudioCodec kPcmuCodec(0, "PCMU", 64000, 8000, 1);
@@ -974,7 +975,7 @@
     typename T::Content content2;
     CreateContent(0, kPcmuCodec, kH264Codec, &content2);
     // Set |content2| to be InActive.
-    content2.set_direction(cricket::MD_INACTIVE);
+    content2.set_direction(RtpTransceiverDirection::kInactive);
 
     EXPECT_TRUE(channel1_->Enable(true));
     EXPECT_TRUE(channel2_->Enable(true));
@@ -1003,7 +1004,7 @@
     EXPECT_FALSE(media_channel2_->sending());  // local InActive
 
     // Update |content2| to be RecvOnly.
-    content2.set_direction(cricket::MD_RECVONLY);
+    content2.set_direction(RtpTransceiverDirection::kRecvOnly);
     EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_PRANSWER, NULL));
     EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_PRANSWER, NULL));
 
@@ -1017,7 +1018,7 @@
     EXPECT_FALSE(media_channel2_->sending());  // local RecvOnly
 
     // Update |content2| to be SendRecv.
-    content2.set_direction(cricket::MD_SENDRECV);
+    content2.set_direction(RtpTransceiverDirection::kSendRecv);
     EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER, NULL));
     EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER, NULL));
 
diff --git a/pc/mediasession.cc b/pc/mediasession.cc
index 9c31f50..0818f3b 100644
--- a/pc/mediasession.cc
+++ b/pc/mediasession.cc
@@ -101,38 +101,6 @@
   return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
 }
 
-RtpTransceiverDirection RtpTransceiverDirectionFromMediaContentDirection(
-    MediaContentDirection direction) {
-  switch (direction) {
-    case MD_SENDRECV:
-      return RtpTransceiverDirection::kSendRecv;
-    case MD_SENDONLY:
-      return RtpTransceiverDirection::kSendOnly;
-    case MD_RECVONLY:
-      return RtpTransceiverDirection::kRecvOnly;
-    case MD_INACTIVE:
-      return RtpTransceiverDirection::kInactive;
-  }
-  RTC_NOTREACHED();
-  return RtpTransceiverDirection::kInactive;
-}
-
-MediaContentDirection MediaContentDirectionFromRtpTransceiverDirection(
-    RtpTransceiverDirection direction) {
-  switch (direction) {
-    case RtpTransceiverDirection::kSendRecv:
-      return MD_SENDRECV;
-    case RtpTransceiverDirection::kSendOnly:
-      return MD_SENDONLY;
-    case RtpTransceiverDirection::kRecvOnly:
-      return MD_RECVONLY;
-    case RtpTransceiverDirection::kInactive:
-      return MD_INACTIVE;
-  }
-  RTC_NOTREACHED();
-  return MD_INACTIVE;
-}
-
 static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
     RtpTransceiverDirection offer,
     RtpTransceiverDirection wants) {
@@ -1176,13 +1144,8 @@
     return false;  // Something went seriously wrong.
   }
 
-  auto offer_rtd =
-      RtpTransceiverDirectionFromMediaContentDirection(offer->direction());
-
-  answer->set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          NegotiateRtpTransceiverDirection(
-              offer_rtd, media_description_options.direction)));
+  answer->set_direction(NegotiateRtpTransceiverDirection(
+      offer->direction(), media_description_options.direction));
   return true;
 }
 
@@ -1260,29 +1223,6 @@
       .description.secure();
 }
 
-std::string MediaContentDirectionToString(MediaContentDirection direction) {
-  std::string dir_str;
-  switch (direction) {
-    case MD_INACTIVE:
-      dir_str = "inactive";
-      break;
-    case MD_SENDONLY:
-      dir_str = "sendonly";
-      break;
-    case MD_RECVONLY:
-      dir_str = "recvonly";
-      break;
-    case MD_SENDRECV:
-      dir_str = "sendrecv";
-      break;
-    default:
-      RTC_NOTREACHED();
-      break;
-  }
-
-  return dir_str;
-}
-
 void MediaDescriptionOptions::AddAudioSender(
     const std::string& track_id,
     const std::vector<std::string>& stream_ids) {
@@ -1932,9 +1872,7 @@
   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
   SetMediaProtocol(secure_transport, audio.get());
 
-  audio->set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          media_description_options.direction));
+  audio->set_direction(media_description_options.direction);
 
   desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
                    media_description_options.stopped, audio.release());
@@ -2004,9 +1942,7 @@
   bool secure_transport = (transport_desc_factory_->secure() != SEC_DISABLED);
   SetMediaProtocol(secure_transport, video.get());
 
-  video->set_direction(
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          media_description_options.direction));
+  video->set_direction(media_description_options.direction);
 
   desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
                    media_description_options.stopped, video.release());
@@ -2125,8 +2061,7 @@
   // and the selected direction in the answer.
   // Note these will be filtered one final time in CreateMediaContentAnswer.
   auto wants_rtd = media_description_options.direction;
-  auto offer_rtd = RtpTransceiverDirectionFromMediaContentDirection(
-      offer_audio_description->direction());
+  auto offer_rtd = offer_audio_description->direction();
   auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
   AudioCodecs supported_audio_codecs =
       GetAudioCodecsForAnswer(offer_rtd, answer_rtd);
diff --git a/pc/mediasession.h b/pc/mediasession.h
index edc9d49..09a103a 100644
--- a/pc/mediasession.h
+++ b/pc/mediasession.h
@@ -39,15 +39,6 @@
 typedef std::vector<CryptoParams> CryptoParamsVec;
 typedef std::vector<webrtc::RtpExtension> RtpHeaderExtensions;
 
-enum MediaContentDirection {
-  MD_INACTIVE,
-  MD_SENDONLY,
-  MD_RECVONLY,
-  MD_SENDRECV
-};
-
-std::string MediaContentDirectionToString(MediaContentDirection direction);
-
 enum CryptoType {
   CT_NONE,
   CT_SDES,
@@ -74,12 +65,6 @@
 // Default RTCP CNAME for unit tests.
 const char kDefaultRtcpCname[] = "DefaultRtcpCname";
 
-webrtc::RtpTransceiverDirection
-RtpTransceiverDirectionFromMediaContentDirection(
-    MediaContentDirection direction);
-MediaContentDirection MediaContentDirectionFromRtpTransceiverDirection(
-    webrtc::RtpTransceiverDirection direction);
-
 // Options for an RtpSender contained with an media description/"m=" section.
 struct SenderOptions {
   std::string track_id;
@@ -171,14 +156,9 @@
     direction_ = direction;
   }
 
-  // MediaContentDirection is deprecated; use RtpTransceiverDirection instead.
-  // TODO(steveanton): Change this method to return RtpTransceiverDirection once
-  // external users have switched to |transceiver_direction()|.
-  MediaContentDirection direction() const {
-    return MediaContentDirectionFromRtpTransceiverDirection(direction_);
-  }
-  void set_direction(MediaContentDirection direction) {
-    direction_ = RtpTransceiverDirectionFromMediaContentDirection(direction);
+  webrtc::RtpTransceiverDirection direction() const { return direction_; }
+  void set_direction(webrtc::RtpTransceiverDirection direction) {
+    direction_ = direction;
   }
 
   bool rtcp_mux() const { return rtcp_mux_; }
diff --git a/pc/mediasession_unittest.cc b/pc/mediasession_unittest.cc
index c2653df..b0a85bb 100644
--- a/pc/mediasession_unittest.cc
+++ b/pc/mediasession_unittest.cc
@@ -34,7 +34,6 @@
 
 using cricket::MediaContentDescription;
 using cricket::MediaSessionDescriptionFactory;
-using cricket::MediaContentDirection;
 using cricket::MediaDescriptionOptions;
 using cricket::MediaSessionOptions;
 using cricket::MediaType;
@@ -72,6 +71,7 @@
 using rtc::CS_AEAD_AES_128_GCM;
 using rtc::CS_AEAD_AES_256_GCM;
 using webrtc::RtpExtension;
+using webrtc::RtpTransceiverDirection;
 
 static const AudioCodec kAudioCodecs1[] = {
     AudioCodec(103, "ISAC", 16000, -1, 1),
@@ -225,8 +225,7 @@
   return mdesc && mdesc->type() == media_type;
 }
 
-static cricket::MediaContentDirection
-GetMediaDirection(const ContentInfo* content) {
+static RtpTransceiverDirection GetMediaDirection(const ContentInfo* content) {
   cricket::MediaContentDescription* desc =
       reinterpret_cast<cricket::MediaContentDescription*>(content->description);
   return desc->direction();
@@ -271,23 +270,21 @@
 // Add a media section to the |session_options|.
 static void AddMediaSection(MediaType type,
                             const std::string& mid,
-                            MediaContentDirection direction,
+                            RtpTransceiverDirection direction,
                             bool stopped,
                             MediaSessionOptions* opts) {
-  opts->media_description_options.push_back(MediaDescriptionOptions(
-      type, mid,
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(direction),
-      stopped));
+  opts->media_description_options.push_back(
+      MediaDescriptionOptions(type, mid, direction, stopped));
 }
 
-static void AddAudioVideoSections(MediaContentDirection direction,
+static void AddAudioVideoSections(RtpTransceiverDirection direction,
                                   MediaSessionOptions* opts) {
   AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, opts);
   AddMediaSection(MEDIA_TYPE_VIDEO, "video", direction, kActive, opts);
 }
 
 static void AddDataSection(cricket::DataChannelType dct,
-                           MediaContentDirection direction,
+                           RtpTransceiverDirection direction,
                            MediaSessionOptions* opts) {
   opts->data_channel_type = dct;
   AddMediaSection(MEDIA_TYPE_DATA, "data", direction, kActive, opts);
@@ -335,8 +332,8 @@
 // (https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00).
 static MediaSessionOptions CreatePlanBMediaSessionOptions() {
   MediaSessionOptions session_options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &session_options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &session_options);
   return session_options;
 }
 
@@ -525,8 +522,9 @@
   void TestCryptoWithBundle(bool offer) {
     f1_.set_secure(SEC_ENABLED);
     MediaSessionOptions options;
-    AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-    AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+    AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+    AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                   &options);
     std::unique_ptr<SessionDescription> ref_desc;
     std::unique_ptr<SessionDescription> desc;
     if (offer) {
@@ -574,8 +572,8 @@
   // |expected_direction_in_answer| in an answer if the offer direction is set
   // to |direction_in_offer| and the answer is willing to both send and receive.
   void TestMediaDirectionInAnswer(
-      cricket::MediaContentDirection direction_in_offer,
-      cricket::MediaContentDirection expected_direction_in_answer) {
+      RtpTransceiverDirection direction_in_offer,
+      RtpTransceiverDirection expected_direction_in_answer) {
     MediaSessionOptions offer_opts;
     AddAudioVideoSections(direction_in_offer, &offer_opts);
 
@@ -588,7 +586,7 @@
     ASSERT_TRUE(vc_offer != NULL);
 
     MediaSessionOptions answer_opts;
-    AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
+    AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
     std::unique_ptr<SessionDescription> answer(
         f2_.CreateAnswer(offer.get(), answer_opts, NULL));
     const AudioContentDescription* acd_answer =
@@ -614,11 +612,11 @@
 
   void TestVideoGcmCipher(bool gcm_offer, bool gcm_answer) {
     MediaSessionOptions offer_opts;
-    AddAudioVideoSections(cricket::MD_RECVONLY, &offer_opts);
+    AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &offer_opts);
     offer_opts.crypto_options.enable_gcm_crypto_suites = gcm_offer;
 
     MediaSessionOptions answer_opts;
-    AddAudioVideoSections(cricket::MD_RECVONLY, &answer_opts);
+    AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &answer_opts);
     answer_opts.crypto_options.enable_gcm_crypto_suites = gcm_answer;
 
     f1_.set_secure(SEC_ENABLED);
@@ -692,7 +690,7 @@
 // Create a typical video offer, and ensure it matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoOffer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
@@ -733,8 +731,8 @@
   ASSERT_EQ(offered_video_codec.id, offered_data_codec.id);
 
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   opts.bundle_enabled = true;
   std::unique_ptr<SessionDescription> offer(f2_.CreateOffer(opts, NULL));
   const VideoContentDescription* vcd =
@@ -761,10 +759,10 @@
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_INACTIVE, kStopped,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kInactive,
+                  kStopped, &opts);
   opts.data_channel_type = cricket::DCT_NONE;
   opts.bundle_enabled = true;
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
@@ -772,8 +770,9 @@
       f2_.CreateAnswer(offer.get(), opts, NULL));
 
   MediaSessionOptions updated_opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &updated_opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &updated_opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &updated_opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &updated_opts);
   updated_opts.bundle_enabled = true;
   std::unique_ptr<SessionDescription> updated_offer(
       f1_.CreateOffer(updated_opts, answer.get()));
@@ -799,8 +798,8 @@
 // Create a RTP data offer, and ensure it matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateRtpDataOffer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
@@ -835,7 +834,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSctpDataOffer) {
   MediaSessionOptions opts;
   opts.bundle_enabled = true;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   f1_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   EXPECT_TRUE(offer.get() != NULL);
@@ -846,7 +845,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateImplicitSctpDataOffer) {
   MediaSessionOptions opts;
   opts.bundle_enabled = true;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   f1_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer1.get() != NULL);
@@ -872,7 +871,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestCreateOfferWithoutLegacyStreams) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   const ContentInfo* ac = offer->GetContentByName("audio");
@@ -891,7 +890,7 @@
 // Creates an audio+video sendonly offer.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSendOnlyOffer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_SENDONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kSendOnly, &opts);
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, 1, &opts);
   AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
@@ -903,23 +902,25 @@
   EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[0], MEDIA_TYPE_AUDIO));
   EXPECT_TRUE(IsMediaContentOfType(&offer->contents()[1], MEDIA_TYPE_VIDEO));
 
-  EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[0]));
-  EXPECT_EQ(cricket::MD_SENDONLY, GetMediaDirection(&offer->contents()[1]));
+  EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
+            GetMediaDirection(&offer->contents()[0]));
+  EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
+            GetMediaDirection(&offer->contents()[1]));
 }
 
 // Verifies that the order of the media contents in the current
 // SessionDescription is preserved in the new SessionDescription.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateOfferContentOrder) {
   MediaSessionOptions opts;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
 
   std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer1.get() != NULL);
   EXPECT_EQ(1u, offer1->contents().size());
   EXPECT_TRUE(IsMediaContentOfType(&offer1->contents()[0], MEDIA_TYPE_DATA));
 
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer2(
       f1_.CreateOffer(opts, offer1.get()));
   ASSERT_TRUE(offer2.get() != NULL);
@@ -927,8 +928,8 @@
   EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[0], MEDIA_TYPE_DATA));
   EXPECT_TRUE(IsMediaContentOfType(&offer2->contents()[1], MEDIA_TYPE_VIDEO));
 
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer3(
       f1_.CreateOffer(opts, offer2.get()));
   ASSERT_TRUE(offer3.get() != NULL);
@@ -993,7 +994,7 @@
 // Create a typical video answer, and ensure it matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
@@ -1044,7 +1045,7 @@
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswer) {
   MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
@@ -1077,7 +1078,7 @@
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerGcm) {
   MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   opts.crypto_options.enable_gcm_crypto_suites = true;
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
@@ -1113,7 +1114,7 @@
 // The answer's use_sctpmap flag should match the offer's.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerUsesSctpmap) {
   MediaSessionOptions opts;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   ContentInfo* dc_offer = offer->GetContentByName("data");
@@ -1134,7 +1135,7 @@
 // The answer's use_sctpmap flag should match the offer's.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateDataAnswerWithoutSctpmap) {
   MediaSessionOptions opts;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   ContentInfo* dc_offer = offer->GetContentByName("data");
@@ -1164,7 +1165,7 @@
   tdf2_.set_secure(SEC_ENABLED);
 
   MediaSessionOptions opts;
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer.get() != nullptr);
   ContentInfo* dc_offer = offer->GetContentByName("data");
@@ -1193,20 +1194,20 @@
   MediaSessionOptions opts;
 
   // Creates a data only offer.
-  AddDataSection(cricket::DCT_SCTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
   std::unique_ptr<SessionDescription> offer1(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer1.get() != NULL);
 
   // Appends audio to the offer.
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer2(
       f1_.CreateOffer(opts, offer1.get()));
   ASSERT_TRUE(offer2.get() != NULL);
 
   // Appends video to the offer.
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer3(
       f1_.CreateOffer(opts, offer2.get()));
   ASSERT_TRUE(offer3.get() != NULL);
@@ -1226,32 +1227,36 @@
 // This test that the media direction is set to send/receive in an answer if
 // the offer is send receive.
 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendReceiveOffer) {
-  TestMediaDirectionInAnswer(cricket::MD_SENDRECV, cricket::MD_SENDRECV);
+  TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendRecv,
+                             RtpTransceiverDirection::kSendRecv);
 }
 
 // This test that the media direction is set to receive only in an answer if
 // the offer is send only.
 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToSendOnlyOffer) {
-  TestMediaDirectionInAnswer(cricket::MD_SENDONLY, cricket::MD_RECVONLY);
+  TestMediaDirectionInAnswer(RtpTransceiverDirection::kSendOnly,
+                             RtpTransceiverDirection::kRecvOnly);
 }
 
 // This test that the media direction is set to send only in an answer if
 // the offer is recv only.
 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToRecvOnlyOffer) {
-  TestMediaDirectionInAnswer(cricket::MD_RECVONLY, cricket::MD_SENDONLY);
+  TestMediaDirectionInAnswer(RtpTransceiverDirection::kRecvOnly,
+                             RtpTransceiverDirection::kSendOnly);
 }
 
 // This test that the media direction is set to inactive in an answer if
 // the offer is inactive.
 TEST_F(MediaSessionDescriptionFactoryTest, CreateAnswerToInactiveOffer) {
-  TestMediaDirectionInAnswer(cricket::MD_INACTIVE, cricket::MD_INACTIVE);
+  TestMediaDirectionInAnswer(RtpTransceiverDirection::kInactive,
+                             RtpTransceiverDirection::kInactive);
 }
 
 // Test that a data content with an unknown protocol is rejected in an answer.
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateDataAnswerToOfferWithUnknownProtocol) {
   MediaSessionOptions opts;
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
@@ -1306,7 +1311,7 @@
 // matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestOfferAnswerWithRtpExtensions) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
   f2_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension2));
@@ -1334,7 +1339,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f1_.set_enable_encrypted_rtp_header_extensions(true);
   f2_.set_enable_encrypted_rtp_header_extensions(true);
@@ -1370,7 +1375,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestOfferAnswerWithEncryptedRtpExtensionsOffer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f1_.set_enable_encrypted_rtp_header_extensions(true);
 
@@ -1405,7 +1410,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestOfferAnswerWithEncryptedRtpExtensionsAnswer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f2_.set_enable_encrypted_rtp_header_extensions(true);
 
@@ -1441,8 +1446,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestCreateAnswerWithoutLegacyStreams) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   std::unique_ptr<SessionDescription> answer(
@@ -1466,8 +1471,8 @@
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestPartial) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   f1_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
@@ -1503,12 +1508,14 @@
 // Create a typical video answer, and ensure it matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateVideoAnswerRtcpMux) {
   MediaSessionOptions offer_opts;
-  AddAudioVideoSections(cricket::MD_SENDRECV, &offer_opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &offer_opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &offer_opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
+                 &offer_opts);
 
   MediaSessionOptions answer_opts;
-  AddAudioVideoSections(cricket::MD_SENDRECV, &answer_opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &answer_opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &answer_opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv,
+                 &answer_opts);
 
   std::unique_ptr<SessionDescription> offer;
   std::unique_ptr<SessionDescription> answer;
@@ -1585,10 +1592,10 @@
 // Create an audio-only answer to a video offer.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAudioAnswerToVideo) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
 
@@ -1607,8 +1614,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateNoDataAnswerToDataOffer) {
   MediaSessionOptions opts = CreatePlanBMediaSessionOptions();
   opts.data_channel_type = cricket::DCT_RTP;
-  AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
 
@@ -1627,8 +1634,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateAnswerToOfferWithRejectedMedia) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   ContentInfo* ac = offer->GetContentByName("audio");
@@ -1661,7 +1668,7 @@
 // adding a new video track and replaces one of the audio tracks.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoOffer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_SENDRECV, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kSendRecv, &opts);
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, 1, &opts);
   AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
@@ -1669,7 +1676,7 @@
   AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
                              {kMediaStream1}, 1, &opts);
 
-  AddDataSection(cricket::DCT_RTP, cricket::MD_SENDRECV, &opts);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kSendRecv, &opts);
   AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
                              {kMediaStream1}, 1, &opts);
   AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
@@ -1809,10 +1816,10 @@
 // Create an offer with simulcast video stream.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateSimulcastVideoOffer) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
   const int num_sim_layers = 3;
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, num_sim_layers, &opts);
@@ -1841,22 +1848,22 @@
 // adding a new video track and removes one of the audio tracks.
 TEST_F(MediaSessionDescriptionFactoryTest, TestCreateMultiStreamVideoAnswer) {
   MediaSessionOptions offer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &offer_opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &offer_opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &offer_opts);
   offer_opts.data_channel_type = cricket::DCT_RTP;
-  AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_RECVONLY, kActive,
-                  &offer_opts);
+  AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &offer_opts);
   f1_.set_secure(SEC_ENABLED);
   f2_.set_secure(SEC_ENABLED);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(offer_opts, NULL));
 
   MediaSessionOptions answer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
+                  kActive, &answer_opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &answer_opts);
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, 1, &answer_opts);
   AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
@@ -1864,8 +1871,8 @@
   AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack2,
                              {kMediaStream1}, 1, &answer_opts);
 
-  AddMediaSection(MEDIA_TYPE_DATA, "data", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
+  AddMediaSection(MEDIA_TYPE_DATA, "data", RtpTransceiverDirection::kSendRecv,
+                  kActive, &answer_opts);
   AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack1,
                              {kMediaStream1}, 1, &answer_opts);
   AttachSenderToMediaSection("data", MEDIA_TYPE_DATA, kDataTrack2,
@@ -1994,7 +2001,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        RespondentCreatesOfferAfterCreatingAnswer) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   std::unique_ptr<SessionDescription> answer(
@@ -2045,8 +2052,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        RespondentCreatesOfferAfterCreatingAnswerWithRtx) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
   // This creates rtx for H264 with the payload type |f1_| uses.
   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
@@ -2094,8 +2101,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        RespondentCreatesOfferAfterCreatingAnswerWithRemappedRtxPayloadType) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   // We specifically choose different preferred payload types for VP8 to
   // trigger the issue.
   cricket::VideoCodec vp8_offerer(100, "VP8");
@@ -2152,8 +2159,8 @@
   f1_.set_video_codecs(f1_codecs);
 
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
 
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, NULL));
   std::unique_ptr<SessionDescription> answer(
@@ -2167,7 +2174,7 @@
   // reference  be the same as an audio codec that was negotiated in the
   // first offer/answer exchange.
   opts.media_description_options.clear();
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
   int used_pl_type = acd->codecs()[0].id;
@@ -2204,7 +2211,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        RespondentCreatesOfferWithRtxAfterCreatingAnswerWithoutRtx) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   std::vector<VideoCodec> f2_codecs = MAKE_VECTOR(kVideoCodecs2);
   // This creates rtx for H264 with the payload type |f2_| uses.
@@ -2242,8 +2249,8 @@
 // Test that RTX is ignored when there is no associated payload type parameter.
 TEST_F(MediaSessionDescriptionFactoryTest, RtxWithoutApt) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
   // This creates RTX without associated payload type parameter.
   AddRtxCodec(VideoCodec(126, cricket::kRtxCodecName), &f1_codecs);
@@ -2286,8 +2293,8 @@
 // type doesn't match the local value.
 TEST_F(MediaSessionDescriptionFactoryTest, FilterOutRtxIfAptDoesntMatch) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
   // This creates RTX for H264 in sender.
   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
@@ -2316,8 +2323,8 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        FilterOutUnsupportedRtxWhenCreatingAnswer) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
   // This creates RTX for H264-SVC in sender.
   AddRtxCodec(VideoCodec::CreateRtxCodec(125, kVideoCodecs1[0].id), &f1_codecs);
@@ -2351,8 +2358,8 @@
 // to add another.
 TEST_F(MediaSessionDescriptionFactoryTest, AddSecondRtxInNewOffer) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_RECVONLY, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &opts);
   std::vector<VideoCodec> f1_codecs = MAKE_VECTOR(kVideoCodecs1);
   // This creates RTX for H264 for the offerer.
   AddRtxCodec(VideoCodec::CreateRtxCodec(126, kVideoCodecs1[1].id), &f1_codecs);
@@ -2386,8 +2393,8 @@
 // generated for each simulcast ssrc and correctly grouped.
 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateMultipleRtxSsrcs) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
   // Add simulcast streams.
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
                              {"stream1label"}, 3, &opts);
@@ -2427,8 +2434,8 @@
 // together with a FEC-FR grouping.
 TEST_F(MediaSessionDescriptionFactoryTest, GenerateFlexfecSsrc) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
   // Add single stream.
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
                              {"stream1label"}, 1, &opts);
@@ -2467,8 +2474,8 @@
 // multiple FlexfecSenders, or through multistream protection.
 TEST_F(MediaSessionDescriptionFactoryTest, SimSsrcsGenerateNoFlexfecSsrcs) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
   // Add simulcast streams.
   AttachSenderToMediaSection("video", MEDIA_TYPE_VIDEO, "stream1",
                              {"stream1label"}, 3, &opts);
@@ -2511,7 +2518,7 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        RespondentCreatesOfferAfterCreatingAnswerWithRtpExtensions) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension1));
   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension1));
@@ -2565,7 +2572,7 @@
 // updated offer (this was previously a bug).
 TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReused) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f1_.set_audio_rtp_header_extensions(MAKE_VECTOR(kAudioRtpExtension3));
   f1_.set_video_rtp_header_extensions(MAKE_VECTOR(kVideoRtpExtension3));
@@ -2600,7 +2607,7 @@
 // Same as "RtpExtensionIdReused" above for encrypted RTP extensions.
 TEST_F(MediaSessionDescriptionFactoryTest, RtpExtensionIdReusedEncrypted) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
 
   f1_.set_enable_encrypted_rtp_header_extensions(true);
   f2_.set_enable_encrypted_rtp_header_extensions(true);
@@ -2676,16 +2683,16 @@
 // ensure the TransportInfo in the SessionDescription matches what we expect.
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudio) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   TestTransportInfo(true, options, false);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestTransportInfoOfferIceRenomination) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   options.media_description_options[0]
       .transport_options.enable_ice_renomination = true;
   TestTransportInfo(true, options, false);
@@ -2693,30 +2700,33 @@
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferAudioCurrent) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   TestTransportInfo(true, options, true);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferMultimedia) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   TestTransportInfo(true, options, false);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestTransportInfoOfferMultimediaCurrent) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   TestTransportInfo(true, options, true);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoOfferBundle) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   options.bundle_enabled = true;
   TestTransportInfo(true, options, false);
 }
@@ -2724,24 +2734,25 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestTransportInfoOfferBundleCurrent) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   options.bundle_enabled = true;
   TestTransportInfo(true, options, true);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerAudio) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   TestTransportInfo(false, options, false);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestTransportInfoAnswerIceRenomination) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   options.media_description_options[0]
       .transport_options.enable_ice_renomination = true;
   TestTransportInfo(false, options, false);
@@ -2750,30 +2761,33 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        TestTransportInfoAnswerAudioCurrent) {
   MediaSessionOptions options;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_RECVONLY, kActive,
-                  &options);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kRecvOnly,
+                  kActive, &options);
   TestTransportInfo(false, options, true);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerMultimedia) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   TestTransportInfo(false, options, false);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestTransportInfoAnswerMultimediaCurrent) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   TestTransportInfo(false, options, true);
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest, TestTransportInfoAnswerBundle) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   options.bundle_enabled = true;
   TestTransportInfo(false, options, false);
 }
@@ -2781,8 +2795,9 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
     TestTransportInfoAnswerBundleCurrent) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
   options.bundle_enabled = true;
   TestTransportInfo(false, options, true);
 }
@@ -2865,7 +2880,7 @@
   tdf1_.set_secure(SEC_ENABLED);
   tdf2_.set_secure(SEC_DISABLED);
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
   std::unique_ptr<SessionDescription> offer, answer;
   const cricket::MediaContentDescription* audio_media_desc;
   const cricket::MediaContentDescription* video_media_desc;
@@ -2982,8 +2997,9 @@
   tdf1_.set_secure(SEC_ENABLED);
   tdf2_.set_secure(SEC_ENABLED);
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
-  AddDataSection(cricket::DCT_RTP, cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
+  AddDataSection(cricket::DCT_RTP, RtpTransceiverDirection::kRecvOnly,
+                 &options);
 
   std::unique_ptr<SessionDescription> offer, answer;
 
@@ -3030,7 +3046,7 @@
 // offer or answer.
 TEST_F(MediaSessionDescriptionFactoryTest, TestVADEnableOption) {
   MediaSessionOptions options;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &options);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &options);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(options, NULL));
   ASSERT_TRUE(offer.get() != NULL);
   const ContentInfo* audio_content = offer->GetContentByName("audio");
@@ -3051,13 +3067,13 @@
 // Test that the generated MIDs match the existing offer.
 TEST_F(MediaSessionDescriptionFactoryTest, TestMIDsMatchesExistingOffer) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified", cricket::MD_RECVONLY,
-                  kActive, &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified", cricket::MD_RECVONLY,
-                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_modified",
+                  RtpTransceiverDirection::kRecvOnly, kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video_modified",
+                  RtpTransceiverDirection::kRecvOnly, kActive, &opts);
   opts.data_channel_type = cricket::DCT_SCTP;
-  AddMediaSection(MEDIA_TYPE_DATA, "data_modified", cricket::MD_SENDRECV,
-                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_DATA, "data_modified",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   // Create offer.
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   std::unique_ptr<SessionDescription> updated_offer(
@@ -3080,23 +3096,23 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateOfferWithMultipleAVMediaSections) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
                              {kMediaStream1}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
                              {kMediaStream2}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
                              {kMediaStream2}, 1, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
@@ -3109,7 +3125,7 @@
           offer->contents()[0].description);
   ASSERT_EQ(1u, acd->streams().size());
   EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
 
   EXPECT_FALSE(offer->contents()[1].rejected);
   const VideoContentDescription* vcd =
@@ -3117,21 +3133,21 @@
           offer->contents()[1].description);
   ASSERT_EQ(1u, vcd->streams().size());
   EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
 
   EXPECT_FALSE(offer->contents()[2].rejected);
   acd = static_cast<const AudioContentDescription*>(
       offer->contents()[2].description);
   ASSERT_EQ(1u, acd->streams().size());
   EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
 
   EXPECT_FALSE(offer->contents()[3].rejected);
   vcd = static_cast<const VideoContentDescription*>(
       offer->contents()[3].description);
   ASSERT_EQ(1u, vcd->streams().size());
   EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
 }
 
 // Test that we can create an answer with multiple media sections of same media
@@ -3139,23 +3155,23 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateAnswerWithMultipleAVMediaSections) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("audio_1", MEDIA_TYPE_AUDIO, kAudioTrack1,
                              {kMediaStream1}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video_1", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video_1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("video_1", MEDIA_TYPE_VIDEO, kVideoTrack1,
                              {kMediaStream1}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio_2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("audio_2", MEDIA_TYPE_AUDIO, kAudioTrack2,
                              {kMediaStream2}, 1, &opts);
 
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video_2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video_2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   AttachSenderToMediaSection("video_2", MEDIA_TYPE_VIDEO, kVideoTrack2,
                              {kMediaStream2}, 1, &opts);
 
@@ -3171,7 +3187,7 @@
           answer->contents()[0].description);
   ASSERT_EQ(1u, acd->streams().size());
   EXPECT_EQ(kAudioTrack1, acd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
 
   EXPECT_FALSE(answer->contents()[1].rejected);
   const VideoContentDescription* vcd =
@@ -3179,21 +3195,21 @@
           answer->contents()[1].description);
   ASSERT_EQ(1u, vcd->streams().size());
   EXPECT_EQ(kVideoTrack1, vcd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
 
   EXPECT_FALSE(answer->contents()[2].rejected);
   acd = static_cast<const AudioContentDescription*>(
       answer->contents()[2].description);
   ASSERT_EQ(1u, acd->streams().size());
   EXPECT_EQ(kAudioTrack2, acd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, acd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, acd->direction());
 
   EXPECT_FALSE(answer->contents()[3].rejected);
   vcd = static_cast<const VideoContentDescription*>(
       answer->contents()[3].description);
   ASSERT_EQ(1u, vcd->streams().size());
   EXPECT_EQ(kVideoTrack2, vcd->streams()[0].id);
-  EXPECT_EQ(cricket::MD_SENDRECV, vcd->direction());
+  EXPECT_EQ(RtpTransceiverDirection::kSendRecv, vcd->direction());
 }
 
 // Test that the media section will be rejected in offer if the corresponding
@@ -3202,10 +3218,10 @@
        CreateOfferWithMediaSectionStoppedByOfferer) {
   // Create an offer with two audio sections and one of them is stopped.
   MediaSessionOptions offer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
-                  &offer_opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
-                  &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
+                  RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
   std::unique_ptr<SessionDescription> offer(
       f1_.CreateOffer(offer_opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3220,10 +3236,10 @@
        CreateAnswerWithMediaSectionStoppedByOfferer) {
   // Create an offer with two audio sections and one of them is stopped.
   MediaSessionOptions offer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
-                  &offer_opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
-                  &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
+                  RtpTransceiverDirection::kInactive, kStopped, &offer_opts);
   std::unique_ptr<SessionDescription> offer(
       f1_.CreateOffer(offer_opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3233,10 +3249,10 @@
 
   // Create an answer based on the offer.
   MediaSessionOptions answer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
   std::unique_ptr<SessionDescription> answer(
       f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
   ASSERT_EQ(2u, answer->contents().size());
@@ -3250,10 +3266,10 @@
        CreateAnswerWithMediaSectionRejectedByAnswerer) {
   // Create an offer with two audio sections.
   MediaSessionOptions offer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
-                  &offer_opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_SENDRECV, kActive,
-                  &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &offer_opts);
   std::unique_ptr<SessionDescription> offer(
       f1_.CreateOffer(offer_opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3263,10 +3279,10 @@
 
   // The answerer rejects one of the audio sections.
   MediaSessionOptions answer_opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1", cricket::MD_SENDRECV, kActive,
-                  &answer_opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2", cricket::MD_INACTIVE, kStopped,
-                  &answer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &answer_opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio2",
+                  RtpTransceiverDirection::kInactive, kStopped, &answer_opts);
   std::unique_ptr<SessionDescription> answer(
       f2_.CreateAnswer(offer.get(), answer_opts, nullptr));
   ASSERT_EQ(2u, answer->contents().size());
@@ -3281,10 +3297,10 @@
   MediaSessionOptions opts;
   // This tests put video section first because normally audio comes first by
   // default.
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
 
   ASSERT_TRUE(offer);
@@ -3298,10 +3314,10 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        PayloadTypesSharedByMediaSectionsOfSameType) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   // Create an offer with two video sections using same codecs.
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3339,10 +3355,10 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateOfferRespectsCodecPreferenceOrder) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   // Create an offer with two video sections using same codecs.
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3376,10 +3392,10 @@
 TEST_F(MediaSessionDescriptionFactoryTest,
        CreateAnswerRespectsCodecPreferenceOrder) {
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video1", cricket::MD_SENDRECV, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video2", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video1",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video2",
+                  RtpTransceiverDirection::kSendRecv, kActive, &opts);
   // Create an offer with two video sections using same codecs.
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3435,10 +3451,10 @@
   f2_.set_video_codecs(video_codecs2);
 
   MediaSessionOptions opts;
-  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", cricket::MD_SENDRECV, kActive,
-                  &opts);
-  AddMediaSection(MEDIA_TYPE_VIDEO, "video", cricket::MD_SENDRECV, kActive,
-                  &opts);
+  AddMediaSection(MEDIA_TYPE_AUDIO, "audio", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
+  AddMediaSection(MEDIA_TYPE_VIDEO, "video", RtpTransceiverDirection::kSendRecv,
+                  kActive, &opts);
 
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer);
@@ -3496,7 +3512,7 @@
 
 TEST_P(MediaProtocolTest, TestAudioVideoAcceptance) {
   MediaSessionOptions opts;
-  AddAudioVideoSections(cricket::MD_RECVONLY, &opts);
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
   std::unique_ptr<SessionDescription> offer(f1_.CreateOffer(opts, nullptr));
   ASSERT_TRUE(offer.get() != nullptr);
   // Set the protocol for all the contents.
@@ -3596,7 +3612,7 @@
   return true;
 }
 
-void TestAudioCodecsOffer(MediaContentDirection direction) {
+void TestAudioCodecsOffer(RtpTransceiverDirection direction) {
   TransportDescriptionFactory tdf;
   MediaSessionDescriptionFactory sf(&tdf);
   const std::vector<AudioCodec> send_codecs = MAKE_VECTOR(kAudioCodecs1);
@@ -3608,7 +3624,8 @@
   MediaSessionOptions opts;
   AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
 
-  if (direction == cricket::MD_SENDRECV || direction == cricket::MD_SENDONLY) {
+  if (direction == RtpTransceiverDirection::kSendRecv ||
+      direction == RtpTransceiverDirection::kSendOnly) {
     AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
                                {kMediaStream1}, 1, &opts);
   }
@@ -3628,9 +3645,9 @@
     // to be used for sending and receiving. Inactive essentially means it
     // might eventually be used anything, but we don't know more at this
     // moment.
-    if (acd->direction() == cricket::MD_SENDONLY) {
+    if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
       EXPECT_TRUE(CodecsMatch<AudioCodec>(send_codecs, acd->codecs()));
-    } else if (acd->direction() == cricket::MD_RECVONLY) {
+    } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
       EXPECT_TRUE(CodecsMatch<AudioCodec>(recv_codecs, acd->codecs()));
     } else {
       EXPECT_TRUE(CodecsMatch<AudioCodec>(sendrecv_codecs, acd->codecs()));
@@ -3689,8 +3706,8 @@
   return out;
 }
 
-void TestAudioCodecsAnswer(MediaContentDirection offer_direction,
-                           MediaContentDirection answer_direction,
+void TestAudioCodecsAnswer(RtpTransceiverDirection offer_direction,
+                           RtpTransceiverDirection answer_direction,
                            bool add_legacy_stream) {
   TransportDescriptionFactory offer_tdf;
   TransportDescriptionFactory answer_tdf;
@@ -3707,8 +3724,7 @@
   AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
                   &offer_opts);
 
-  if (webrtc::RtpTransceiverDirectionHasSend(
-          RtpTransceiverDirectionFromMediaContentDirection(offer_direction))) {
+  if (webrtc::RtpTransceiverDirectionHasSend(offer_direction)) {
     AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
                                {kMediaStream1}, 1, &offer_opts);
   }
@@ -3721,8 +3737,7 @@
   AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
                   &answer_opts);
 
-  if (webrtc::RtpTransceiverDirectionHasSend(
-          RtpTransceiverDirectionFromMediaContentDirection(answer_direction))) {
+  if (webrtc::RtpTransceiverDirectionHasSend(answer_direction)) {
     AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
                                {kMediaStream1}, 1, &answer_opts);
   }
@@ -3743,23 +3758,23 @@
     // For offers with sendrecv or inactive, we should never reply with more
     // codecs than offered, with these codec sets.
     switch (offer_direction) {
-      case cricket::MD_INACTIVE:
+      case RtpTransceiverDirection::kInactive:
         target_codecs = VectorFromIndices(kOfferAnswerCodecs,
                                           kResultSendrecv_SendrecvCodecs);
         break;
-      case cricket::MD_SENDONLY:
+      case RtpTransceiverDirection::kSendOnly:
         target_codecs =
             VectorFromIndices(kOfferAnswerCodecs, kResultSend_RecvCodecs);
         break;
-      case cricket::MD_RECVONLY:
+      case RtpTransceiverDirection::kRecvOnly:
         target_codecs =
             VectorFromIndices(kOfferAnswerCodecs, kResultRecv_SendCodecs);
         break;
-      case cricket::MD_SENDRECV:
-        if (acd->direction() == cricket::MD_SENDONLY) {
+      case RtpTransceiverDirection::kSendRecv:
+        if (acd->direction() == RtpTransceiverDirection::kSendOnly) {
           target_codecs =
               VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_SendCodecs);
-        } else if (acd->direction() == cricket::MD_RECVONLY) {
+        } else if (acd->direction() == RtpTransceiverDirection::kRecvOnly) {
           target_codecs =
               VectorFromIndices(kOfferAnswerCodecs, kResultSendrecv_RecvCodecs);
         } else {
@@ -3783,13 +3798,14 @@
 
     EXPECT_TRUE(acd->codecs() == target_codecs)
         << "Expected: " << format_codecs(target_codecs)
-        << ", got: " << format_codecs(acd->codecs())
-        << "; Offered: " << MediaContentDirectionToString(offer_direction)
+        << ", got: " << format_codecs(acd->codecs()) << "; Offered: "
+        << webrtc::RtpTransceiverDirectionToString(offer_direction)
         << ", answerer wants: "
-        << MediaContentDirectionToString(answer_direction)
-        << "; got: " << MediaContentDirectionToString(acd->direction());
+        << webrtc::RtpTransceiverDirectionToString(answer_direction)
+        << "; got: "
+        << webrtc::RtpTransceiverDirectionToString(acd->direction());
   } else {
-    EXPECT_EQ(offer_direction, cricket::MD_INACTIVE)
+    EXPECT_EQ(offer_direction, RtpTransceiverDirection::kInactive)
         << "Only inactive offers are allowed to not generate any audio "
            "content";
   }
@@ -3798,7 +3814,7 @@
 }  // namespace
 
 class AudioCodecsOfferTest
-    : public ::testing::TestWithParam<MediaContentDirection> {};
+    : public ::testing::TestWithParam<RtpTransceiverDirection> {};
 
 TEST_P(AudioCodecsOfferTest, TestCodecsInOffer) {
   TestAudioCodecsOffer(GetParam());
@@ -3806,14 +3822,14 @@
 
 INSTANTIATE_TEST_CASE_P(MediaSessionDescriptionFactoryTest,
                         AudioCodecsOfferTest,
-                        ::testing::Values(cricket::MD_SENDONLY,
-                                          cricket::MD_RECVONLY,
-                                          cricket::MD_SENDRECV,
-                                          cricket::MD_INACTIVE));
+                        ::testing::Values(RtpTransceiverDirection::kSendOnly,
+                                          RtpTransceiverDirection::kRecvOnly,
+                                          RtpTransceiverDirection::kSendRecv,
+                                          RtpTransceiverDirection::kInactive));
 
 class AudioCodecsAnswerTest
-    : public ::testing::TestWithParam<::testing::tuple<MediaContentDirection,
-                                                       MediaContentDirection,
+    : public ::testing::TestWithParam<::testing::tuple<RtpTransceiverDirection,
+                                                       RtpTransceiverDirection,
                                                        bool>> {};
 
 TEST_P(AudioCodecsAnswerTest, TestCodecsInAnswer) {
@@ -3825,12 +3841,12 @@
 INSTANTIATE_TEST_CASE_P(
     MediaSessionDescriptionFactoryTest,
     AudioCodecsAnswerTest,
-    ::testing::Combine(::testing::Values(cricket::MD_SENDONLY,
-                                         cricket::MD_RECVONLY,
-                                         cricket::MD_SENDRECV,
-                                         cricket::MD_INACTIVE),
-                       ::testing::Values(cricket::MD_SENDONLY,
-                                         cricket::MD_RECVONLY,
-                                         cricket::MD_SENDRECV,
-                                         cricket::MD_INACTIVE),
+    ::testing::Combine(::testing::Values(RtpTransceiverDirection::kSendOnly,
+                                         RtpTransceiverDirection::kRecvOnly,
+                                         RtpTransceiverDirection::kSendRecv,
+                                         RtpTransceiverDirection::kInactive),
+                       ::testing::Values(RtpTransceiverDirection::kSendOnly,
+                                         RtpTransceiverDirection::kRecvOnly,
+                                         RtpTransceiverDirection::kSendRecv,
+                                         RtpTransceiverDirection::kInactive),
                        ::testing::Bool()));
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 0011ad7..01f31dd 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -148,16 +148,12 @@
   return true;
 }
 
-bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
-  return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
-}
-
 // If the direction is "recvonly" or "inactive", treat the description
 // as containing no streams.
 // See: https://code.google.com/p/webrtc/issues/detail?id=5054
 std::vector<cricket::StreamParams> GetActiveStreams(
     const cricket::MediaContentDescription* desc) {
-  return MediaContentDirectionHasSend(desc->direction())
+  return RtpTransceiverDirectionHasSend(desc->direction())
              ? desc->streams()
              : std::vector<cricket::StreamParams>();
 }
@@ -1772,7 +1768,7 @@
     } else {
       bool default_audio_track_needed =
           !remote_peer_supports_msid_ &&
-          MediaContentDirectionHasSend(audio_desc->direction());
+          RtpTransceiverDirectionHasSend(audio_desc->direction());
       UpdateRemoteSendersList(GetActiveStreams(audio_desc),
                               default_audio_track_needed, audio_desc->type(),
                               new_streams);
@@ -1787,7 +1783,7 @@
     } else {
       bool default_video_track_needed =
           !remote_peer_supports_msid_ &&
-          MediaContentDirectionHasSend(video_desc->direction());
+          RtpTransceiverDirectionHasSend(video_desc->direction());
       UpdateRemoteSendersList(GetActiveStreams(video_desc),
                               default_video_track_needed, video_desc->type(),
                               new_streams);
diff --git a/pc/peerconnection_media_unittest.cc b/pc/peerconnection_media_unittest.cc
index 9f4da02..1e8b296 100644
--- a/pc/peerconnection_media_unittest.cc
+++ b/pc/peerconnection_media_unittest.cc
@@ -113,7 +113,7 @@
     return static_cast<const cricket::MediaContentDescription*>(content_desc);
   }
 
-  cricket::MediaContentDirection GetMediaContentDirection(
+  RtpTransceiverDirection GetMediaContentDirection(
       const SessionDescriptionInterface* sdesc,
       const std::string& mid) {
     auto* media_content = GetMediaContent(sdesc, mid);
@@ -339,7 +339,7 @@
 class PeerConnectionMediaOfferDirectionTest
     : public PeerConnectionMediaTest,
       public ::testing::WithParamInterface<
-          std::tuple<bool, int, cricket::MediaContentDirection>> {
+          std::tuple<bool, int, RtpTransceiverDirection>> {
  protected:
   PeerConnectionMediaOfferDirectionTest() {
     send_media_ = std::get<0>(GetParam());
@@ -349,7 +349,7 @@
 
   bool send_media_;
   int offer_to_receive_;
-  cricket::MediaContentDirection expected_direction_;
+  RtpTransceiverDirection expected_direction_;
 };
 
 // Tests that the correct direction is set on the media description according
@@ -365,7 +365,7 @@
   auto offer = caller->CreateOffer(options);
 
   auto* media_content = GetMediaContent(offer.get(), cricket::CN_AUDIO);
-  if (expected_direction_ == cricket::MD_INACTIVE) {
+  if (expected_direction_ == RtpTransceiverDirection::kInactive) {
     EXPECT_FALSE(media_content);
   } else {
     EXPECT_EQ(expected_direction_, media_content->direction());
@@ -374,19 +374,20 @@
 
 // Note that in these tests, MD_INACTIVE indicates that no media section is
 // included in the offer, not that the media direction is inactive.
-INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
-                        PeerConnectionMediaOfferDirectionTest,
-                        Values(std::make_tuple(false, -1, cricket::MD_INACTIVE),
-                               std::make_tuple(false, 0, cricket::MD_INACTIVE),
-                               std::make_tuple(false, 1, cricket::MD_RECVONLY),
-                               std::make_tuple(true, -1, cricket::MD_SENDRECV),
-                               std::make_tuple(true, 0, cricket::MD_SENDONLY),
-                               std::make_tuple(true, 1, cricket::MD_SENDRECV)));
+INSTANTIATE_TEST_CASE_P(
+    PeerConnectionMediaTest,
+    PeerConnectionMediaOfferDirectionTest,
+    Values(std::make_tuple(false, -1, RtpTransceiverDirection::kInactive),
+           std::make_tuple(false, 0, RtpTransceiverDirection::kInactive),
+           std::make_tuple(false, 1, RtpTransceiverDirection::kRecvOnly),
+           std::make_tuple(true, -1, RtpTransceiverDirection::kSendRecv),
+           std::make_tuple(true, 0, RtpTransceiverDirection::kSendOnly),
+           std::make_tuple(true, 1, RtpTransceiverDirection::kSendRecv)));
 
 class PeerConnectionMediaAnswerDirectionTest
     : public PeerConnectionMediaTest,
       public ::testing::WithParamInterface<
-          std::tuple<cricket::MediaContentDirection, bool, int>> {
+          std::tuple<RtpTransceiverDirection, bool, int>> {
  protected:
   PeerConnectionMediaAnswerDirectionTest() {
     offer_direction_ = std::get<0>(GetParam());
@@ -394,7 +395,7 @@
     offer_to_receive_ = std::get<2>(GetParam());
   }
 
-  cricket::MediaContentDirection offer_direction_;
+  RtpTransceiverDirection offer_direction_;
   bool send_media_;
   int offer_to_receive_;
 };
@@ -429,19 +430,15 @@
   // 1. Send if the answerer has a local track to send.
   // 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
   //    if it has been left as default.
-  auto offer_direction =
-      cricket::RtpTransceiverDirectionFromMediaContentDirection(
-          offer_direction_);
-  bool offer_send = RtpTransceiverDirectionHasSend(offer_direction);
-  bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction);
+  bool offer_send = RtpTransceiverDirectionHasSend(offer_direction_);
+  bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction_);
 
   // The negotiated components determine the direction set in the answer.
   bool negotiate_send = (send_media_ && offer_recv);
   bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
 
   auto expected_direction =
-      cricket::MediaContentDirectionFromRtpTransceiverDirection(
-          RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv));
+      RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv);
   EXPECT_EQ(expected_direction,
             GetMediaContentDirection(answer.get(), cricket::CN_AUDIO));
 }
@@ -478,10 +475,10 @@
 
 INSTANTIATE_TEST_CASE_P(PeerConnectionMediaTest,
                         PeerConnectionMediaAnswerDirectionTest,
-                        Combine(Values(cricket::MD_INACTIVE,
-                                       cricket::MD_SENDONLY,
-                                       cricket::MD_RECVONLY,
-                                       cricket::MD_SENDRECV),
+                        Combine(Values(RtpTransceiverDirection::kInactive,
+                                       RtpTransceiverDirection::kSendOnly,
+                                       RtpTransceiverDirection::kRecvOnly,
+                                       RtpTransceiverDirection::kSendRecv),
                                 Bool(),
                                 Values(-1, 0, 1)));
 
@@ -494,9 +491,9 @@
   options.offer_to_receive_video = 0;
   auto offer = caller->CreateOffer(options);
 
-  EXPECT_EQ(cricket::MD_RECVONLY,
+  EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
             GetMediaContentDirection(offer.get(), cricket::CN_AUDIO));
-  EXPECT_EQ(cricket::MD_SENDONLY,
+  EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
             GetMediaContentDirection(offer.get(), cricket::CN_VIDEO));
 }
 
@@ -512,9 +509,9 @@
   options.offer_to_receive_video = 0;
   auto answer = callee->CreateAnswer(options);
 
-  EXPECT_EQ(cricket::MD_RECVONLY,
+  EXPECT_EQ(RtpTransceiverDirection::kRecvOnly,
             GetMediaContentDirection(answer.get(), cricket::CN_AUDIO));
-  EXPECT_EQ(cricket::MD_SENDONLY,
+  EXPECT_EQ(RtpTransceiverDirection::kSendOnly,
             GetMediaContentDirection(answer.get(), cricket::CN_VIDEO));
 }
 
diff --git a/pc/peerconnectioninterface_unittest.cc b/pc/peerconnectioninterface_unittest.cc
index 8d0c6f4..abe5666 100644
--- a/pc/peerconnectioninterface_unittest.cc
+++ b/pc/peerconnectioninterface_unittest.cc
@@ -350,6 +350,7 @@
 using webrtc::RTCErrorType;
 using webrtc::RtpReceiverInterface;
 using webrtc::RtpSenderInterface;
+using webrtc::RtpTransceiverDirection;
 using webrtc::SdpParseError;
 using webrtc::SessionDescriptionInterface;
 using webrtc::StreamCollection;
@@ -2203,14 +2204,14 @@
   const cricket::VideoContentDescription* video_desc =
       static_cast<const cricket::VideoContentDescription*>(
           video_content->description);
-  ASSERT_EQ(cricket::MD_RECVONLY, video_desc->direction());
+  ASSERT_EQ(RtpTransceiverDirection::kRecvOnly, video_desc->direction());
 
   const cricket::ContentInfo* audio_content =
       cricket::GetFirstAudioContent(offer->description());
   const cricket::AudioContentDescription* audio_desc =
       static_cast<const cricket::AudioContentDescription*>(
           audio_content->description);
-  ASSERT_EQ(cricket::MD_RECVONLY, audio_desc->direction());
+  ASSERT_EQ(RtpTransceiverDirection::kRecvOnly, audio_desc->direction());
 }
 
 // Test that if we're receiving (but not sending) a track, and the
@@ -2240,14 +2241,14 @@
   const cricket::VideoContentDescription* video_desc =
       static_cast<const cricket::VideoContentDescription*>(
           video_content->description);
-  ASSERT_EQ(cricket::MD_INACTIVE, video_desc->direction());
+  ASSERT_EQ(RtpTransceiverDirection::kInactive, video_desc->direction());
 
   const cricket::ContentInfo* audio_content =
       cricket::GetFirstAudioContent(offer->description());
   const cricket::AudioContentDescription* audio_desc =
       static_cast<const cricket::AudioContentDescription*>(
           audio_content->description);
-  ASSERT_EQ(cricket::MD_INACTIVE, audio_desc->direction());
+  ASSERT_EQ(RtpTransceiverDirection::kInactive, audio_desc->direction());
 }
 
 // Test that we can use SetConfiguration to change the ICE servers of the
diff --git a/pc/rtpmediautils.cc b/pc/rtpmediautils.cc
index ef86c0a..f88861c 100644
--- a/pc/rtpmediautils.cc
+++ b/pc/rtpmediautils.cc
@@ -50,4 +50,19 @@
   return direction;
 }
 
+const char* RtpTransceiverDirectionToString(RtpTransceiverDirection direction) {
+  switch (direction) {
+    case RtpTransceiverDirection::kSendRecv:
+      return "kSendRecv";
+    case RtpTransceiverDirection::kSendOnly:
+      return "kSendOnly";
+    case RtpTransceiverDirection::kRecvOnly:
+      return "kRecvOnly";
+    case RtpTransceiverDirection::kInactive:
+      return "kInactive";
+  }
+  RTC_NOTREACHED();
+  return "";
+}
+
 }  // namespace webrtc
diff --git a/pc/rtpmediautils.h b/pc/rtpmediautils.h
index 96426f4..6f547bd 100644
--- a/pc/rtpmediautils.h
+++ b/pc/rtpmediautils.h
@@ -31,6 +31,9 @@
 RtpTransceiverDirection RtpTransceiverDirectionReversed(
     RtpTransceiverDirection direction);
 
+// Returns an unspecified string representation of the given direction.
+const char* RtpTransceiverDirectionToString(RtpTransceiverDirection direction);
+
 }  // namespace webrtc
 
 #endif  // PC_RTPMEDIAUTILS_H_
diff --git a/pc/webrtcsdp.cc b/pc/webrtcsdp.cc
index 8101a70..63265cd 100644
--- a/pc/webrtcsdp.cc
+++ b/pc/webrtcsdp.cc
@@ -1466,16 +1466,16 @@
   // RFC 3264
   // a=sendrecv || a=sendonly || a=sendrecv || a=inactive
   switch (media_desc->direction()) {
-    case cricket::MD_INACTIVE:
+    case RtpTransceiverDirection::kInactive:
       InitAttrLine(kAttributeInactive, &os);
       break;
-    case cricket::MD_SENDONLY:
+    case RtpTransceiverDirection::kSendOnly:
       InitAttrLine(kAttributeSendOnly, &os);
       break;
-    case cricket::MD_RECVONLY:
+    case RtpTransceiverDirection::kRecvOnly:
       InitAttrLine(kAttributeRecvOnly, &os);
       break;
-    case cricket::MD_SENDRECV:
+    case RtpTransceiverDirection::kSendRecv:
     default:
       InitAttrLine(kAttributeSendRecv, &os);
       break;
@@ -2880,13 +2880,13 @@
           return false;
         }
       } else if (HasAttribute(line, kAttributeSendOnly)) {
-        media_desc->set_direction(cricket::MD_SENDONLY);
+        media_desc->set_direction(RtpTransceiverDirection::kSendOnly);
       } else if (HasAttribute(line, kAttributeRecvOnly)) {
-        media_desc->set_direction(cricket::MD_RECVONLY);
+        media_desc->set_direction(RtpTransceiverDirection::kRecvOnly);
       } else if (HasAttribute(line, kAttributeInactive)) {
-        media_desc->set_direction(cricket::MD_INACTIVE);
+        media_desc->set_direction(RtpTransceiverDirection::kInactive);
       } else if (HasAttribute(line, kAttributeSendRecv)) {
-        media_desc->set_direction(cricket::MD_SENDRECV);
+        media_desc->set_direction(RtpTransceiverDirection::kSendRecv);
       } else if (HasAttribute(line, kAttributeExtmap)) {
         RtpExtension extmap;
         if (!ParseExtmap(line, &extmap, error)) {
diff --git a/pc/webrtcsdp_unittest.cc b/pc/webrtcsdp_unittest.cc
index 2c88c33..c4cd7db 100644
--- a/pc/webrtcsdp_unittest.cc
+++ b/pc/webrtcsdp_unittest.cc
@@ -57,6 +57,7 @@
 using webrtc::JsepIceCandidate;
 using webrtc::JsepSessionDescription;
 using webrtc::RtpExtension;
+using webrtc::RtpTransceiverDirection;
 using webrtc::SdpParseError;
 using webrtc::SessionDescriptionInterface;
 
@@ -825,20 +826,20 @@
   ExpectParseFailure(bad_sdp, bad_part);
 }
 
-static void ReplaceDirection(cricket::MediaContentDirection direction,
+static void ReplaceDirection(RtpTransceiverDirection direction,
                              std::string* message) {
   std::string new_direction;
   switch (direction) {
-    case cricket::MD_INACTIVE:
+    case RtpTransceiverDirection::kInactive:
       new_direction = "a=inactive";
       break;
-    case cricket::MD_SENDONLY:
+    case RtpTransceiverDirection::kSendOnly:
       new_direction = "a=sendonly";
       break;
-    case cricket::MD_RECVONLY:
+    case RtpTransceiverDirection::kRecvOnly:
       new_direction = "a=recvonly";
       break;
-    case cricket::MD_SENDRECV:
+    case RtpTransceiverDirection::kSendRecv:
     default:
       new_direction = "a=sendrecv";
       break;
@@ -1457,7 +1458,7 @@
     video_desc_->set_cryptos(std::vector<CryptoParams>());
   }
 
-  bool TestSerializeDirection(cricket::MediaContentDirection direction) {
+  bool TestSerializeDirection(RtpTransceiverDirection direction) {
     audio_desc_->set_direction(direction);
     video_desc_->set_direction(direction);
     std::string new_sdp = kSdpFullString;
@@ -1534,7 +1535,7 @@
         kDataContentName, TransportDescription(kUfragData, kPwdData))));
   }
 
-  bool TestDeserializeDirection(cricket::MediaContentDirection direction) {
+  bool TestDeserializeDirection(RtpTransceiverDirection direction) {
     std::string new_sdp = kSdpFullString;
     ReplaceDirection(direction, &new_sdp);
     JsepSessionDescription new_jdesc(kDummyString);
@@ -1932,15 +1933,15 @@
 }
 
 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithRecvOnlyContent) {
-  EXPECT_TRUE(TestSerializeDirection(cricket::MD_RECVONLY));
+  EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kRecvOnly));
 }
 
 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithSendOnlyContent) {
-  EXPECT_TRUE(TestSerializeDirection(cricket::MD_SENDONLY));
+  EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kSendOnly));
 }
 
 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithInactiveContent) {
-  EXPECT_TRUE(TestSerializeDirection(cricket::MD_INACTIVE));
+  EXPECT_TRUE(TestSerializeDirection(RtpTransceiverDirection::kInactive));
 }
 
 TEST_F(WebRtcSdpTest, SerializeSessionDescriptionWithAudioRejected) {
@@ -2330,15 +2331,15 @@
 }
 
 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRecvOnlyContent) {
-  EXPECT_TRUE(TestDeserializeDirection(cricket::MD_RECVONLY));
+  EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kRecvOnly));
 }
 
 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithSendOnlyContent) {
-  EXPECT_TRUE(TestDeserializeDirection(cricket::MD_SENDONLY));
+  EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kSendOnly));
 }
 
 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithInactiveContent) {
-  EXPECT_TRUE(TestDeserializeDirection(cricket::MD_INACTIVE));
+  EXPECT_TRUE(TestDeserializeDirection(RtpTransceiverDirection::kInactive));
 }
 
 TEST_F(WebRtcSdpTest, DeserializeSessionDescriptionWithRejectedAudio) {