Create the SrtpTransportInterface.

Create the SrtpTransportInterface, a subclass of RtpTransportInterface, which
allows the user to set the send and receive keys. The functionalities are
implemented inside the RtpTransportAdapters on top of BaseChannel.

BUG=webrtc:7013

Review-Url: https://codereview.webrtc.org/2714813004
Cr-Commit-Position: refs/heads/master@{#17023}
diff --git a/webrtc/api/BUILD.gn b/webrtc/api/BUILD.gn
index 716f8c9..3447e92 100644
--- a/webrtc/api/BUILD.gn
+++ b/webrtc/api/BUILD.gn
@@ -94,6 +94,7 @@
     "ortc/packettransportinterface.h",
     "ortc/rtptransportcontrollerinterface.h",
     "ortc/rtptransportinterface.h",
+    "ortc/srtptransportinterface.h",
     "ortc/udptransportinterface.h",
   ]
 
diff --git a/webrtc/api/ortc/ortcfactoryinterface.h b/webrtc/api/ortc/ortcfactoryinterface.h
index 855e3b0..62ed90d 100644
--- a/webrtc/api/ortc/ortcfactoryinterface.h
+++ b/webrtc/api/ortc/ortcfactoryinterface.h
@@ -23,6 +23,7 @@
 #include "webrtc/api/ortc/packettransportinterface.h"
 #include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
 #include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
 #include "webrtc/api/ortc/udptransportinterface.h"
 #include "webrtc/api/rtcerror.h"
 #include "webrtc/api/rtpparameters.h"
@@ -126,6 +127,14 @@
       PacketTransportInterface* rtcp,
       RtpTransportControllerInterface* transport_controller) = 0;
 
+  // Creates an SrtpTransport which is an RTP transport that uses SRTP.
+  virtual RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+  CreateSrtpTransport(
+      const RtcpParameters& rtcp_parameters,
+      PacketTransportInterface* rtp,
+      PacketTransportInterface* rtcp,
+      RtpTransportControllerInterface* transport_controller) = 0;
+
   // Returns the capabilities of an RTP sender of type |kind|. These
   // capabilities can be used to determine what RtpParameters to use to create
   // an RtpSender.
diff --git a/webrtc/api/ortc/ortcrtpsenderinterface.h b/webrtc/api/ortc/ortcrtpsenderinterface.h
index e369b53..a0fc208 100644
--- a/webrtc/api/ortc/ortcrtpsenderinterface.h
+++ b/webrtc/api/ortc/ortcrtpsenderinterface.h
@@ -18,8 +18,8 @@
 #ifndef WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
 #define WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
 
-#include "webrtc/api/mediatypes.h"
 #include "webrtc/api/mediastreaminterface.h"
+#include "webrtc/api/mediatypes.h"
 #include "webrtc/api/ortc/rtptransportinterface.h"
 #include "webrtc/api/rtcerror.h"
 #include "webrtc/api/rtpparameters.h"
diff --git a/webrtc/api/ortc/srtptransportinterface.h b/webrtc/api/ortc/srtptransportinterface.h
new file mode 100644
index 0000000..f64618c
--- /dev/null
+++ b/webrtc/api/ortc/srtptransportinterface.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
+#define WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
+
+#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/rtcerror.h"
+#include "webrtc/media/base/cryptoparams.h"
+
+namespace webrtc {
+
+// The subclass of the RtpTransport which uses SRTP. The keying information
+// is explicitly passed in from the application.
+//
+// If using SDP and SDES (RFC4568) for signaling, then after applying the
+// answer, the negotiated keying information from the offer and answer would be
+// set and the SRTP would be active.
+//
+// Note that Edge's implementation of ORTC provides a similar API point, called
+// RTCSrtpSdesTransport:
+// https://msdn.microsoft.com/en-us/library/mt502527(v=vs.85).aspx
+class SrtpTransportInterface : public RtpTransportInterface {
+ public:
+  virtual ~SrtpTransportInterface() {}
+
+  // There are some limitations of the current implementation:
+  //  1. Send and receive keys must use the same crypto suite.
+  //  2. The keys can't be changed after initially set.
+  //  3. The keys must be set before creating a sender/receiver using the SRTP
+  //     transport.
+  // Set the SRTP keying material for sending RTP and RTCP.
+  virtual RTCError SetSrtpSendKey(const cricket::CryptoParams& params) = 0;
+
+  // Set the SRTP keying material for receiving RTP and RTCP.
+  virtual RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
diff --git a/webrtc/api/rtpparameters.h b/webrtc/api/rtpparameters.h
index e4fe47b..a428804 100644
--- a/webrtc/api/rtpparameters.h
+++ b/webrtc/api/rtpparameters.h
@@ -16,8 +16,8 @@
 #include <vector>
 
 #include "webrtc/api/mediatypes.h"
-#include "webrtc/config.h"
 #include "webrtc/base/optional.h"
+#include "webrtc/config.h"
 
 namespace webrtc {
 
diff --git a/webrtc/ortc/BUILD.gn b/webrtc/ortc/BUILD.gn
index ebba3b8..9e1c18f 100644
--- a/webrtc/ortc/BUILD.gn
+++ b/webrtc/ortc/BUILD.gn
@@ -58,6 +58,7 @@
       "rtpparametersconversion_unittest.cc",
       "rtptransport_unittest.cc",
       "rtptransportcontroller_unittest.cc",
+      "srtptransport_unittest.cc",
       "testrtpparameters.cc",
       "testrtpparameters.h",
     ]
diff --git a/webrtc/ortc/ortcfactory.cc b/webrtc/ortc/ortcfactory.cc
index c0d54d1..8af6191 100644
--- a/webrtc/ortc/ortcfactory.cc
+++ b/webrtc/ortc/ortcfactory.cc
@@ -11,11 +11,11 @@
 #include "webrtc/ortc/ortcfactory.h"
 
 #include <sstream>
-#include <vector>
 #include <utility>  // For std::move.
+#include <vector>
 
-#include "webrtc/api/proxy.h"
 #include "webrtc/api/mediastreamtrackproxy.h"
+#include "webrtc/api/proxy.h"
 #include "webrtc/api/rtcerror.h"
 #include "webrtc/api/videosourceproxy.h"
 #include "webrtc/base/asyncpacketsocket.h"
@@ -33,9 +33,9 @@
 #include "webrtc/ortc/rtptransportcontrolleradapter.h"
 #include "webrtc/p2p/base/basicpacketsocketfactory.h"
 #include "webrtc/p2p/base/udptransport.h"
+#include "webrtc/pc/audiotrack.h"
 #include "webrtc/pc/channelmanager.h"
 #include "webrtc/pc/localaudiosource.h"
-#include "webrtc/pc/audiotrack.h"
 #include "webrtc/pc/videocapturertracksource.h"
 #include "webrtc/pc/videotrack.h"
 
@@ -78,6 +78,14 @@
               PacketTransportInterface*,
               PacketTransportInterface*,
               RtpTransportControllerInterface*)
+
+PROXY_METHOD4(RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>,
+              CreateSrtpTransport,
+              const RtcpParameters&,
+              PacketTransportInterface*,
+              PacketTransportInterface*,
+              RtpTransportControllerInterface*)
+
 PROXY_CONSTMETHOD1(RtpCapabilities,
                    GetRtpSenderCapabilities,
                    cricket::MediaType)
@@ -250,6 +258,43 @@
   }
 }
 
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+OrtcFactory::CreateSrtpTransport(
+    const RtcpParameters& rtcp_parameters,
+    PacketTransportInterface* rtp,
+    PacketTransportInterface* rtcp,
+    RtpTransportControllerInterface* transport_controller) {
+  RTC_DCHECK_RUN_ON(signaling_thread_);
+  RtcpParameters copied_parameters = rtcp_parameters;
+  if (copied_parameters.cname.empty()) {
+    copied_parameters.cname = default_cname_;
+  }
+  if (transport_controller) {
+    return transport_controller->GetInternal()->CreateProxiedSrtpTransport(
+        copied_parameters, rtp, rtcp);
+  } else {
+    // If |transport_controller| is null, create one automatically, which the
+    // returned SrtpTransport will own.
+    auto controller_result = CreateRtpTransportController();
+    if (!controller_result.ok()) {
+      return controller_result.MoveError();
+    }
+    auto controller = controller_result.MoveValue();
+    auto transport_result =
+        controller->GetInternal()->CreateProxiedSrtpTransport(copied_parameters,
+                                                              rtp, rtcp);
+    // If SrtpTransport was successfully created, transfer ownership of
+    // |rtp_transport_controller|. Otherwise it will go out of scope and be
+    // deleted automatically.
+    if (transport_result.ok()) {
+      transport_result.value()
+          ->GetInternal()
+          ->TakeOwnershipOfRtpTransportController(std::move(controller));
+    }
+    return transport_result;
+  }
+}
+
 RtpCapabilities OrtcFactory::GetRtpSenderCapabilities(
     cricket::MediaType kind) const {
   RTC_DCHECK_RUN_ON(signaling_thread_);
diff --git a/webrtc/ortc/ortcfactory.h b/webrtc/ortc/ortcfactory.h
index 71f525d..8d67a3f 100644
--- a/webrtc/ortc/ortcfactory.h
+++ b/webrtc/ortc/ortcfactory.h
@@ -49,6 +49,12 @@
       PacketTransportInterface* rtcp,
       RtpTransportControllerInterface* transport_controller) override;
 
+  RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpTransport(
+      const RtcpParameters& rtcp_parameters,
+      PacketTransportInterface* rtp,
+      PacketTransportInterface* rtcp,
+      RtpTransportControllerInterface* transport_controller) override;
+
   RtpCapabilities GetRtpSenderCapabilities(
       cricket::MediaType kind) const override;
 
diff --git a/webrtc/ortc/ortcfactory_integrationtest.cc b/webrtc/ortc/ortcfactory_integrationtest.cc
index e935f06..0f782b2 100644
--- a/webrtc/ortc/ortcfactory_integrationtest.cc
+++ b/webrtc/ortc/ortcfactory_integrationtest.cc
@@ -25,13 +25,38 @@
 
 namespace {
 
-const int kDefaultTimeout = 10000;  // 10 seconds.
+const int kDefaultTimeout = 10000;    // 10 seconds.
+const int kReceivingDuration = 1000;  // 1 second.
 // Default number of audio/video frames to wait for before considering a test a
 // success.
 const int kDefaultNumFrames = 3;
 const rtc::IPAddress kIPv4LocalHostAddress =
     rtc::IPAddress(0x7F000001);  // 127.0.0.1
 
+static const char kTestKeyParams1[] =
+    "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVz";
+static const char kTestKeyParams2[] =
+    "inline:PS1uQCVeeCFCanVmcjkpaywjNWhcYD0mXXtxaVBR";
+static const char kTestKeyParams3[] =
+    "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVa";
+static const char kTestKeyParams4[] =
+    "inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVb";
+static const cricket::CryptoParams kTestCryptoParams1(1,
+                                                      "AES_CM_128_HMAC_SHA1_80",
+                                                      kTestKeyParams1,
+                                                      "");
+static const cricket::CryptoParams kTestCryptoParams2(1,
+                                                      "AES_CM_128_HMAC_SHA1_80",
+                                                      kTestKeyParams2,
+                                                      "");
+static const cricket::CryptoParams kTestCryptoParams3(1,
+                                                      "AES_CM_128_HMAC_SHA1_80",
+                                                      kTestKeyParams3,
+                                                      "");
+static const cricket::CryptoParams kTestCryptoParams4(1,
+                                                      "AES_CM_128_HMAC_SHA1_80",
+                                                      kTestKeyParams4,
+                                                      "");
 }  // namespace
 
 namespace webrtc {
@@ -71,6 +96,9 @@
   typedef std::pair<std::unique_ptr<RtpTransportInterface>,
                     std::unique_ptr<RtpTransportInterface>>
       RtpTransportPair;
+  typedef std::pair<std::unique_ptr<SrtpTransportInterface>,
+                    std::unique_ptr<SrtpTransportInterface>>
+      SrtpTransportPair;
   typedef std::pair<std::unique_ptr<RtpTransportControllerInterface>,
                     std::unique_ptr<RtpTransportControllerInterface>>
       RtpTransportControllerPair;
@@ -115,6 +143,20 @@
     return {transport_result1.MoveValue(), transport_result2.MoveValue()};
   }
 
+  SrtpTransportPair CreateSrtpTransportPair(
+      const RtcpParameters& rtcp_parameters,
+      const UdpTransportPair& rtp_udp_transports,
+      const UdpTransportPair& rtcp_udp_transports,
+      const RtpTransportControllerPair& transport_controllers) {
+    auto transport_result1 = ortc_factory1_->CreateSrtpTransport(
+        rtcp_parameters, rtp_udp_transports.first.get(),
+        rtcp_udp_transports.first.get(), transport_controllers.first.get());
+    auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
+        rtcp_parameters, rtp_udp_transports.second.get(),
+        rtcp_udp_transports.second.get(), transport_controllers.second.get());
+    return {transport_result1.MoveValue(), transport_result2.MoveValue()};
+  }
+
   // For convenience when |rtcp_udp_transports| and |transport_controllers|
   // aren't needed.
   RtpTransportPair CreateRtpTransportPair(
@@ -125,6 +167,38 @@
                                   RtpTransportControllerPair());
   }
 
+  SrtpTransportPair CreateSrtpTransportPairAndSetKeys(
+      const RtcpParameters& rtcp_parameters,
+      const UdpTransportPair& rtp_udp_transports) {
+    SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
+        rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
+        RtpTransportControllerPair());
+    EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
+    EXPECT_TRUE(
+        srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+    EXPECT_TRUE(
+        srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2).ok());
+    EXPECT_TRUE(
+        srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1).ok());
+    return srtp_transports;
+  }
+
+  SrtpTransportPair CreateSrtpTransportPairAndSetMismatchingKeys(
+      const RtcpParameters& rtcp_parameters,
+      const UdpTransportPair& rtp_udp_transports) {
+    SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
+        rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
+        RtpTransportControllerPair());
+    EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
+    EXPECT_TRUE(
+        srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+    EXPECT_TRUE(
+        srtp_transports.second->SetSrtpSendKey(kTestCryptoParams1).ok());
+    EXPECT_TRUE(
+        srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+    return srtp_transports;
+  }
+
   // Ends up using fake audio capture module, which was passed into OrtcFactory
   // on creation.
   rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack(
@@ -152,6 +226,110 @@
         ortc_factory->CreateVideoTrack(id, source));
   }
 
+  // Helper function used to test two way RTP senders and receivers with basic
+  // configurations.
+  // If |expect_success| is true, waits for kDefaultTimeout for
+  // kDefaultNumFrames frames to be received by all RtpReceivers.
+  // If |expect_success| is false, simply waits for |kReceivingDuration|, and
+  // stores the number of received frames in |received_audio_frame1_| etc.
+  void BasicTwoWayRtpSendersAndReceiversTest(RtpTransportPair srtp_transports,
+                                             bool expect_success) {
+    received_audio_frames1_ = 0;
+    received_audio_frames2_ = 0;
+    rendered_video_frames1_ = 0;
+    rendered_video_frames2_ = 0;
+    // Create all the senders and receivers (four per endpoint).
+    auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
+        cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
+    auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
+        cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
+    auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
+        cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
+    auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
+        cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
+    ASSERT_TRUE(audio_sender_result1.ok());
+    ASSERT_TRUE(video_sender_result1.ok());
+    ASSERT_TRUE(audio_receiver_result1.ok());
+    ASSERT_TRUE(video_receiver_result1.ok());
+    auto audio_sender1 = audio_sender_result1.MoveValue();
+    auto video_sender1 = video_sender_result1.MoveValue();
+    auto audio_receiver1 = audio_receiver_result1.MoveValue();
+    auto video_receiver1 = video_receiver_result1.MoveValue();
+
+    auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
+        cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
+    auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
+        cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
+    auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
+        cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
+    auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
+        cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
+    ASSERT_TRUE(audio_sender_result2.ok());
+    ASSERT_TRUE(video_sender_result2.ok());
+    ASSERT_TRUE(audio_receiver_result2.ok());
+    ASSERT_TRUE(video_receiver_result2.ok());
+    auto audio_sender2 = audio_sender_result2.MoveValue();
+    auto video_sender2 = video_sender_result2.MoveValue();
+    auto audio_receiver2 = audio_receiver_result2.MoveValue();
+    auto video_receiver2 = video_receiver_result2.MoveValue();
+
+    // Add fake tracks.
+    RTCError error = audio_sender1->SetTrack(
+        CreateLocalAudioTrack("audio", ortc_factory1_.get()));
+    EXPECT_TRUE(error.ok());
+    error = video_sender1->SetTrack(
+        CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
+    EXPECT_TRUE(error.ok());
+    error = audio_sender2->SetTrack(
+        CreateLocalAudioTrack("audio", ortc_factory2_.get()));
+    EXPECT_TRUE(error.ok());
+    error = video_sender2->SetTrack(
+        CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
+    EXPECT_TRUE(error.ok());
+
+    // "sent_X_parameters1" are the parameters that endpoint 1 sends with and
+    // endpoint 2 receives with.
+    RtpParameters sent_opus_parameters1 =
+        MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
+    RtpParameters sent_vp8_parameters1 =
+        MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
+    RtpParameters sent_opus_parameters2 =
+        MakeMinimalOpusParametersWithSsrc(0x13333337);
+    RtpParameters sent_vp8_parameters2 =
+        MakeMinimalVp8ParametersWithSsrc(0x12345678);
+
+    // Configure the senders' and receivers' parameters.
+    EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
+    EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
+    EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
+    EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
+    EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
+    EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
+    EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
+    EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
+
+    FakeVideoTrackRenderer fake_video_renderer1(
+        static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
+    FakeVideoTrackRenderer fake_video_renderer2(
+        static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
+
+    if (expect_success) {
+      EXPECT_TRUE_WAIT(
+          fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
+              fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
+              fake_audio_capture_module2_->frames_received() >
+                  kDefaultNumFrames &&
+              fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames,
+          kDefaultTimeout);
+    } else {
+      WAIT(false, kReceivingDuration);
+      rendered_video_frames1_ = fake_video_renderer1.num_rendered_frames();
+      rendered_video_frames2_ = fake_video_renderer2.num_rendered_frames();
+      received_audio_frames1_ = fake_audio_capture_module1_->frames_received();
+      received_audio_frames2_ = fake_audio_capture_module2_->frames_received();
+    }
+  }
+
   rtc::PhysicalSocketServer physical_socket_server_;
   rtc::VirtualSocketServer virtual_socket_server_;
   rtc::Thread network_thread_;
@@ -162,6 +340,10 @@
   std::unique_ptr<OrtcFactoryInterface> ortc_factory2_;
   // Actually owned by video tracks.
   std::vector<cricket::FakeVideoCapturer*> fake_video_capturers_;
+  int received_audio_frames1_ = 0;
+  int received_audio_frames2_ = 0;
+  int rendered_video_frames1_ = 0;
+  int rendered_video_frames2_ = 0;
 };
 
 // Very basic end-to-end test with a single pair of audio RTP sender and
@@ -285,102 +467,75 @@
   auto udp_transports = CreateAndConnectUdpTransportPair();
   auto rtp_transports =
       CreateRtpTransportPair(MakeRtcpMuxParameters(), udp_transports);
+  bool expect_success = true;
+  BasicTwoWayRtpSendersAndReceiversTest(std::move(rtp_transports),
+                                        expect_success);
+}
 
-  // Create all the senders and receivers (four per endpoint).
-  auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
-      cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
-  auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
-      cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
-  auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
-  auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
-  ASSERT_TRUE(audio_sender_result1.ok());
-  ASSERT_TRUE(video_sender_result1.ok());
-  ASSERT_TRUE(audio_receiver_result1.ok());
-  ASSERT_TRUE(video_receiver_result1.ok());
-  auto audio_sender1 = audio_sender_result1.MoveValue();
-  auto video_sender1 = video_sender_result1.MoveValue();
-  auto audio_receiver1 = audio_receiver_result1.MoveValue();
-  auto video_receiver1 = video_receiver_result1.MoveValue();
+TEST_F(OrtcFactoryIntegrationTest,
+       BasicTwoWayAudioVideoSrtpSendersAndReceivers) {
+  auto udp_transports = CreateAndConnectUdpTransportPair();
+  auto srtp_transports = CreateSrtpTransportPairAndSetKeys(
+      MakeRtcpMuxParameters(), udp_transports);
+  bool expect_success = true;
+  BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
+                                        expect_success);
+}
 
-  auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
-      cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
-  auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
-      cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
-  auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
-  auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
-  ASSERT_TRUE(audio_sender_result2.ok());
-  ASSERT_TRUE(video_sender_result2.ok());
-  ASSERT_TRUE(audio_receiver_result2.ok());
-  ASSERT_TRUE(video_receiver_result2.ok());
-  auto audio_sender2 = audio_sender_result2.MoveValue();
-  auto video_sender2 = video_sender_result2.MoveValue();
-  auto audio_receiver2 = audio_receiver_result2.MoveValue();
-  auto video_receiver2 = video_receiver_result2.MoveValue();
+// Tests that the packets cannot be decoded if the keys are mismatched.
+TEST_F(OrtcFactoryIntegrationTest, SrtpSendersAndReceiversWithMismatchingKeys) {
+  auto udp_transports = CreateAndConnectUdpTransportPair();
+  auto srtp_transports = CreateSrtpTransportPairAndSetMismatchingKeys(
+      MakeRtcpMuxParameters(), udp_transports);
+  bool expect_success = false;
+  BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
+                                        expect_success);
+  // No frames are expected to be decoded.
+  EXPECT_TRUE(received_audio_frames1_ == 0 && received_audio_frames2_ == 0 &&
+              rendered_video_frames1_ == 0 && rendered_video_frames2_ == 0);
+}
 
-  // Add fake tracks.
-  RTCError error = audio_sender1->SetTrack(
-      CreateLocalAudioTrack("audio", ortc_factory1_.get()));
-  EXPECT_TRUE(error.ok());
-  error = video_sender1->SetTrack(
-      CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
-  EXPECT_TRUE(error.ok());
-  error = audio_sender2->SetTrack(
-      CreateLocalAudioTrack("audio", ortc_factory2_.get()));
-  EXPECT_TRUE(error.ok());
-  error = video_sender2->SetTrack(
-      CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
-  EXPECT_TRUE(error.ok());
+// Tests that the frames cannot be decoded if only one side uses SRTP.
+TEST_F(OrtcFactoryIntegrationTest, OneSideSrtpSenderAndReceiver) {
+  auto rtcp_parameters = MakeRtcpMuxParameters();
+  auto udp_transports = CreateAndConnectUdpTransportPair();
+  auto rtcp_udp_transports = UdpTransportPair();
+  auto transport_controllers = RtpTransportControllerPair();
+  auto transport_result1 = ortc_factory1_->CreateRtpTransport(
+      rtcp_parameters, udp_transports.first.get(),
+      rtcp_udp_transports.first.get(), transport_controllers.first.get());
+  auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
+      rtcp_parameters, udp_transports.second.get(),
+      rtcp_udp_transports.second.get(), transport_controllers.second.get());
 
-  // "sent_X_parameters1" are the parameters that endpoint 1 sends with and
-  // endpoint 2 receives with.
-  RtpParameters sent_opus_parameters1 =
-      MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
-  RtpParameters sent_vp8_parameters1 =
-      MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
-  RtpParameters sent_opus_parameters2 =
-      MakeMinimalOpusParametersWithSsrc(0x13333337);
-  RtpParameters sent_vp8_parameters2 =
-      MakeMinimalVp8ParametersWithSsrc(0x12345678);
+  auto rtp_transport = transport_result1.MoveValue();
+  auto srtp_transport = transport_result2.MoveValue();
+  EXPECT_TRUE(srtp_transport->SetSrtpSendKey(kTestCryptoParams1).ok());
+  EXPECT_TRUE(srtp_transport->SetSrtpReceiveKey(kTestCryptoParams2).ok());
+  bool expect_success = false;
+  BasicTwoWayRtpSendersAndReceiversTest(
+      {std::move(rtp_transport), std::move(srtp_transport)}, expect_success);
 
-  // Configure the senders' and receivers' parameters.
-  EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
-  EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
-  EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
-  EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
-  EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
-  EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
-  EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
-  EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
-
-  FakeVideoTrackRenderer fake_video_renderer1(
-      static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
-  FakeVideoTrackRenderer fake_video_renderer2(
-      static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
-
-  // Senders and receivers are connected and configured; audio and video frames
-  // should be able to flow at this point.
-  EXPECT_TRUE_WAIT(
-      fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
-          fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
-          fake_audio_capture_module2_->frames_received() > kDefaultNumFrames &&
-          fake_video_renderer2.num_rendered_frames() > kDefaultNumFrames,
-      kDefaultTimeout);
+  // The SRTP side is not expected to decode any audio or video frames.
+  // The RTP side is not expected to decode any video frames while it is
+  // possible that the encrypted audio frames can be accidentally decoded which
+  // is why received_audio_frames1_ is not validated.
+  EXPECT_TRUE(received_audio_frames2_ == 0 && rendered_video_frames1_ == 0 &&
+              rendered_video_frames2_ == 0);
 }
 
 // End-to-end test with two pairs of RTP senders and receivers, for audio and
 // video. Unlike the test above, this attempts to make the parameters as
-// complex as possible.
+// complex as possible. The senders and receivers use the SRTP transport with
+// different keys.
 //
 // Uses non-muxed RTCP, with separate audio/video transports, and a full set of
 // parameters, as would normally be used in a PeerConnection.
 //
 // TODO(deadbeef): Update this test as more audio/video features become
 // supported.
-TEST_F(OrtcFactoryIntegrationTest, FullTwoWayAudioVideoRtpSendersAndReceivers) {
+TEST_F(OrtcFactoryIntegrationTest,
+       FullTwoWayAudioVideoSrtpSendersAndReceivers) {
   // We want four pairs of UDP transports for this test, for audio/video and
   // RTP/RTCP.
   auto audio_rtp_udp_transports = CreateAndConnectUdpTransportPair();
@@ -394,26 +549,37 @@
 
   RtcpParameters audio_rtcp_parameters;
   audio_rtcp_parameters.mux = false;
-  auto audio_rtp_transports =
-      CreateRtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
-                             audio_rtcp_udp_transports, transport_controllers);
+  auto audio_srtp_transports =
+      CreateSrtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
+                              audio_rtcp_udp_transports, transport_controllers);
 
   RtcpParameters video_rtcp_parameters;
   video_rtcp_parameters.mux = false;
   video_rtcp_parameters.reduced_size = true;
-  auto video_rtp_transports =
-      CreateRtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
-                             video_rtcp_udp_transports, transport_controllers);
+  auto video_srtp_transports =
+      CreateSrtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
+                              video_rtcp_udp_transports, transport_controllers);
+
+  // Set keys for SRTP transports.
+  audio_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1);
+  audio_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2);
+  video_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams3);
+  video_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams4);
+
+  audio_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2);
+  audio_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1);
+  video_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams4);
+  video_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams3);
 
   // Create all the senders and receivers (four per endpoint).
   auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
-      cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
+      cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
   auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
-      cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
+      cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
   auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
+      cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
   auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
+      cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
   ASSERT_TRUE(audio_sender_result1.ok());
   ASSERT_TRUE(video_sender_result1.ok());
   ASSERT_TRUE(audio_receiver_result1.ok());
@@ -424,13 +590,13 @@
   auto video_receiver1 = video_receiver_result1.MoveValue();
 
   auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
-      cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
+      cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
   auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
-      cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
+      cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
   auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
+      cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
   auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
-      cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
+      cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
   ASSERT_TRUE(audio_sender_result2.ok());
   ASSERT_TRUE(video_sender_result2.ok());
   ASSERT_TRUE(audio_receiver_result2.ok());
diff --git a/webrtc/ortc/ortcfactory_unittest.cc b/webrtc/ortc/ortcfactory_unittest.cc
index 80e679b..200939a 100644
--- a/webrtc/ortc/ortcfactory_unittest.cc
+++ b/webrtc/ortc/ortcfactory_unittest.cc
@@ -82,6 +82,24 @@
   EXPECT_TRUE(result.ok());
 }
 
+// Simple test for the successful cases of CreateSrtpTransport.
+TEST_F(OrtcFactoryTest, CreateSrtpTransport) {
+  rtc::FakePacketTransport rtp("rtp");
+  rtc::FakePacketTransport rtcp("rtcp");
+  // With muxed RTCP.
+  RtcpParameters rtcp_parameters;
+  rtcp_parameters.mux = true;
+  auto result = ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp,
+                                                   nullptr, nullptr);
+  EXPECT_TRUE(result.ok());
+  result.MoveValue().reset();
+  // With non-muxed RTCP.
+  rtcp_parameters.mux = false;
+  result =
+      ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp, &rtcp, nullptr);
+  EXPECT_TRUE(result.ok());
+}
+
 // If no CNAME is provided, one should be generated and returned by
 // GetRtpParameters.
 TEST_F(OrtcFactoryTest, CreateRtpTransportGeneratesCname) {
diff --git a/webrtc/ortc/ortcrtpreceiver_unittest.cc b/webrtc/ortc/ortcrtpreceiver_unittest.cc
index 1764af0..aa7d81d 100644
--- a/webrtc/ortc/ortcrtpreceiver_unittest.cc
+++ b/webrtc/ortc/ortcrtpreceiver_unittest.cc
@@ -12,9 +12,9 @@
 
 #include "webrtc/base/gunit.h"
 #include "webrtc/media/base/fakemediaengine.h"
-#include "webrtc/p2p/base/fakepackettransport.h"
 #include "webrtc/ortc/ortcfactory.h"
 #include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
 #include "webrtc/pc/test/fakevideotracksource.h"
 
 namespace webrtc {
diff --git a/webrtc/ortc/ortcrtpsender_unittest.cc b/webrtc/ortc/ortcrtpsender_unittest.cc
index 954b997..47cb337 100644
--- a/webrtc/ortc/ortcrtpsender_unittest.cc
+++ b/webrtc/ortc/ortcrtpsender_unittest.cc
@@ -12,9 +12,9 @@
 
 #include "webrtc/base/gunit.h"
 #include "webrtc/media/base/fakemediaengine.h"
-#include "webrtc/p2p/base/fakepackettransport.h"
 #include "webrtc/ortc/ortcfactory.h"
 #include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
 #include "webrtc/pc/test/fakevideotracksource.h"
 
 namespace webrtc {
diff --git a/webrtc/ortc/rtpparametersconversion.h b/webrtc/ortc/rtpparametersconversion.h
index a1680a2..a466895 100644
--- a/webrtc/ortc/rtpparametersconversion.h
+++ b/webrtc/ortc/rtpparametersconversion.h
@@ -17,8 +17,8 @@
 #include "webrtc/api/rtcerror.h"
 #include "webrtc/api/rtpparameters.h"
 #include "webrtc/base/optional.h"
-#include "webrtc/pc/mediasession.h"
 #include "webrtc/media/base/codec.h"
+#include "webrtc/pc/mediasession.h"
 
 namespace webrtc {
 
diff --git a/webrtc/ortc/rtptransportadapter.cc b/webrtc/ortc/rtptransportadapter.cc
index 439f9a8..3982f2d 100644
--- a/webrtc/ortc/rtptransportadapter.cc
+++ b/webrtc/ortc/rtptransportadapter.cc
@@ -32,6 +32,20 @@
 }
 END_PROXY_MAP()
 
+BEGIN_OWNED_PROXY_MAP(SrtpTransport)
+PROXY_SIGNALING_THREAD_DESTRUCTOR()
+PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtpPacketTransport)
+PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtcpPacketTransport)
+PROXY_METHOD1(RTCError, SetRtcpParameters, const RtcpParameters&)
+PROXY_CONSTMETHOD0(RtcpParameters, GetRtcpParameters)
+PROXY_METHOD1(RTCError, SetSrtpSendKey, const cricket::CryptoParams&)
+PROXY_METHOD1(RTCError, SetSrtpReceiveKey, const cricket::CryptoParams&)
+protected:
+RtpTransportAdapter* GetInternal() override {
+  return internal();
+}
+END_PROXY_MAP()
+
 // static
 RTCErrorOr<std::unique_ptr<RtpTransportInterface>>
 RtpTransportAdapter::CreateProxied(
@@ -64,7 +78,43 @@
       rtp_transport_controller->signaling_thread(),
       rtp_transport_controller->worker_thread(),
       std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
-          rtcp_parameters, rtp, rtcp, rtp_transport_controller)));
+          rtcp_parameters, rtp, rtcp, rtp_transport_controller,
+          /*is_srtp_transport*/ false)));
+}
+
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+RtpTransportAdapter::CreateSrtpProxied(
+    const RtcpParameters& rtcp_parameters,
+    PacketTransportInterface* rtp,
+    PacketTransportInterface* rtcp,
+    RtpTransportControllerAdapter* rtp_transport_controller) {
+  if (!rtp) {
+    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+                         "Must provide an RTP packet transport.");
+  }
+  if (!rtcp_parameters.mux && !rtcp) {
+    LOG_AND_RETURN_ERROR(
+        RTCErrorType::INVALID_PARAMETER,
+        "Must provide an RTCP packet transport when RTCP muxing is not used.");
+  }
+  if (rtcp_parameters.mux && rtcp) {
+    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+                         "Creating an RtpTransport with RTCP muxing enabled, "
+                         "with a separate RTCP packet transport?");
+  }
+  if (!rtp_transport_controller) {
+    // Since OrtcFactory::CreateRtpTransport creates an RtpTransportController
+    // automatically when one isn't passed in, this should never be reached.
+    RTC_NOTREACHED();
+    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
+                         "Must provide an RTP transport controller.");
+  }
+  return SrtpTransportProxyWithInternal<RtpTransportAdapter>::Create(
+      rtp_transport_controller->signaling_thread(),
+      rtp_transport_controller->worker_thread(),
+      std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
+          rtcp_parameters, rtp, rtcp, rtp_transport_controller,
+          /*is_srtp_transport*/ true)));
 }
 
 void RtpTransportAdapter::TakeOwnershipOfRtpTransportController(
@@ -78,11 +128,13 @@
     const RtcpParameters& rtcp_parameters,
     PacketTransportInterface* rtp,
     PacketTransportInterface* rtcp,
-    RtpTransportControllerAdapter* rtp_transport_controller)
+    RtpTransportControllerAdapter* rtp_transport_controller,
+    bool is_srtp_transport)
     : rtp_packet_transport_(rtp),
       rtcp_packet_transport_(rtcp),
       rtp_transport_controller_(rtp_transport_controller),
-      rtcp_parameters_(rtcp_parameters) {
+      rtcp_parameters_(rtcp_parameters),
+      is_srtp_transport_(is_srtp_transport) {
   RTC_DCHECK(rtp_transport_controller);
   // CNAME should have been filled by OrtcFactory if empty.
   RTC_DCHECK(!rtcp_parameters_.cname.empty());
@@ -126,4 +178,36 @@
   return RTCError::OK();
 }
 
+RTCError RtpTransportAdapter::SetSrtpSendKey(
+    const cricket::CryptoParams& params) {
+  if (send_key_) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "Setting the SRTP send key twice is currently unsupported.");
+  }
+  if (receive_key_ && receive_key_->cipher_suite != params.cipher_suite) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "The send key and receive key must have the same cipher suite.");
+  }
+  send_key_ = rtc::Optional<cricket::CryptoParams>(params);
+  return RTCError::OK();
+}
+
+RTCError RtpTransportAdapter::SetSrtpReceiveKey(
+    const cricket::CryptoParams& params) {
+  if (receive_key_) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "Setting the SRTP receive key twice is currently unsupported.");
+  }
+  if (send_key_ && send_key_->cipher_suite != params.cipher_suite) {
+    LOG_AND_RETURN_ERROR(
+        webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
+        "The send key and receive key must have the same cipher suite.");
+  }
+  receive_key_ = rtc::Optional<cricket::CryptoParams>(params);
+  return RTCError::OK();
+}
+
 }  // namespace webrtc
diff --git a/webrtc/ortc/rtptransportadapter.h b/webrtc/ortc/rtptransportadapter.h
index 169ae61..59a123e 100644
--- a/webrtc/ortc/rtptransportadapter.h
+++ b/webrtc/ortc/rtptransportadapter.h
@@ -14,7 +14,7 @@
 #include <memory>
 #include <vector>
 
-#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
 #include "webrtc/api/rtcerror.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/sigslot.h"
@@ -24,13 +24,14 @@
 
 namespace webrtc {
 
-// Implementation of RtpTransportInterface to be used with RtpSenderAdapter,
-// RtpReceiverAdapter, and RtpTransportControllerAdapter classes.
+// Implementation of SrtpTransportInterface to be used with RtpSenderAdapter,
+// RtpReceiverAdapter, and RtpTransportControllerAdapter classes. This class
+// is used to implement both a secure and insecure RTP transport.
 //
 // TODO(deadbeef): When BaseChannel is split apart into separate
 // "RtpTransport"/"RtpTransceiver"/"RtpSender"/"RtpReceiver" objects, this
 // adapter object can be removed.
-class RtpTransportAdapter : public RtpTransportInterface {
+class RtpTransportAdapter : public SrtpTransportInterface {
  public:
   // |rtp| can't be null. |rtcp| can if RTCP muxing is used immediately (meaning
   // |rtcp_parameters.mux| is also true).
@@ -39,6 +40,13 @@
       PacketTransportInterface* rtp,
       PacketTransportInterface* rtcp,
       RtpTransportControllerAdapter* rtp_transport_controller);
+
+  static RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpProxied(
+      const RtcpParameters& rtcp_parameters,
+      PacketTransportInterface* rtp,
+      PacketTransportInterface* rtcp,
+      RtpTransportControllerAdapter* rtp_transport_controller);
+
   ~RtpTransportAdapter() override;
 
   // RtpTransportInterface implementation.
@@ -47,6 +55,10 @@
   RTCError SetRtcpParameters(const RtcpParameters& parameters) override;
   RtcpParameters GetRtcpParameters() const override { return rtcp_parameters_; }
 
+  // SRTP specific implementation.
+  RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override;
+  RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override;
+
   // Methods used internally by OrtcFactory.
   RtpTransportControllerAdapter* rtp_transport_controller() {
     return rtp_transport_controller_;
@@ -58,6 +70,14 @@
   // returning this transport from GetTransports().
   sigslot::signal1<RtpTransportAdapter*> SignalDestroyed;
 
+  // Used by the RtpTransportControllerAdapter to tell if an rtp sender or
+  // receiver can be created.
+  bool is_srtp_transport() { return is_srtp_transport_; }
+  // Used by the RtpTransportControllerAdapter to set keys for senders and
+  // receivers.
+  rtc::Optional<cricket::CryptoParams> send_key() { return send_key_; }
+  rtc::Optional<cricket::CryptoParams> receive_key() { return receive_key_; }
+
  protected:
   RtpTransportAdapter* GetInternal() override { return this; }
 
@@ -65,7 +85,8 @@
   RtpTransportAdapter(const RtcpParameters& rtcp_parameters,
                       PacketTransportInterface* rtp,
                       PacketTransportInterface* rtcp,
-                      RtpTransportControllerAdapter* rtp_transport_controller);
+                      RtpTransportControllerAdapter* rtp_transport_controller,
+                      bool is_srtp_transport);
 
   PacketTransportInterface* rtp_packet_transport_;
   PacketTransportInterface* rtcp_packet_transport_;
@@ -75,6 +96,11 @@
       owned_rtp_transport_controller_;
   RtcpParameters rtcp_parameters_;
 
+  // SRTP specific members.
+  rtc::Optional<cricket::CryptoParams> send_key_;
+  rtc::Optional<cricket::CryptoParams> receive_key_;
+  bool is_srtp_transport_;
+
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpTransportAdapter);
 };
 
diff --git a/webrtc/ortc/rtptransportcontrolleradapter.cc b/webrtc/ortc/rtptransportcontrolleradapter.cc
index 08e943a..ad5d8b5 100644
--- a/webrtc/ortc/rtptransportcontrolleradapter.cc
+++ b/webrtc/ortc/rtptransportcontrolleradapter.cc
@@ -11,8 +11,8 @@
 #include "webrtc/ortc/rtptransportcontrolleradapter.h"
 
 #include <algorithm>  // For "remove", "find".
-#include <sstream>
 #include <set>
+#include <sstream>
 #include <unordered_map>
 #include <utility>  // For std::move.
 
@@ -138,6 +138,21 @@
   return result;
 }
 
+RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+RtpTransportControllerAdapter::CreateProxiedSrtpTransport(
+    const RtcpParameters& rtcp_parameters,
+    PacketTransportInterface* rtp,
+    PacketTransportInterface* rtcp) {
+  auto result =
+      RtpTransportAdapter::CreateSrtpProxied(rtcp_parameters, rtp, rtcp, this);
+  if (result.ok()) {
+    transport_proxies_.push_back(result.value().get());
+    transport_proxies_.back()->GetInternal()->SignalDestroyed.connect(
+        this, &RtpTransportControllerAdapter::OnRtpTransportDestroyed);
+  }
+  return result;
+}
+
 RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
 RtpTransportControllerAdapter::CreateProxiedRtpSender(
     cricket::MediaType kind,
@@ -605,6 +620,11 @@
                          "RtpSender and RtpReceiver is not currently "
                          "supported.");
   }
+  RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
+                                 &remote_audio_description_);
+  if (!err.ok()) {
+    return err;
+  }
   // If setting new transport, extract its RTCP parameters and create voice
   // channel.
   if (!inner_audio_transport_) {
@@ -635,6 +655,11 @@
                          "RtpSender and RtpReceiver is not currently "
                          "supported.");
   }
+  RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
+                                 &remote_video_description_);
+  if (!err.ok()) {
+    return err;
+  }
   // If setting new transport, extract its RTCP parameters and create video
   // channel.
   if (!inner_video_transport_) {
@@ -665,6 +690,11 @@
                          "RtpReceiver and RtpReceiver is not currently "
                          "supported.");
   }
+  RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
+                                 &remote_audio_description_);
+  if (!err.ok()) {
+    return err;
+  }
   // If setting new transport, extract its RTCP parameters and create voice
   // channel.
   if (!inner_audio_transport_) {
@@ -695,6 +725,11 @@
                          "RtpReceiver and RtpReceiver is not currently "
                          "supported.");
   }
+  RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
+                                 &remote_video_description_);
+  if (!err.ok()) {
+    return err;
+  }
   // If setting new transport, extract its RTCP parameters and create video
   // channel.
   if (!inner_video_transport_) {
@@ -896,4 +931,25 @@
   return result;
 }
 
+RTCError RtpTransportControllerAdapter::MaybeSetCryptos(
+    RtpTransportInterface* rtp_transport,
+    cricket::MediaContentDescription* local_description,
+    cricket::MediaContentDescription* remote_description) {
+  if (rtp_transport->GetInternal()->is_srtp_transport()) {
+    if (!rtp_transport->GetInternal()->send_key() ||
+        !rtp_transport->GetInternal()->receive_key()) {
+      LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER,
+                           "The SRTP send key or receive key is not set.")
+    }
+    std::vector<cricket::CryptoParams> cryptos;
+    cryptos.push_back(*(rtp_transport->GetInternal()->receive_key()));
+    local_description->set_cryptos(cryptos);
+
+    cryptos.clear();
+    cryptos.push_back(*(rtp_transport->GetInternal()->send_key()));
+    remote_description->set_cryptos(cryptos);
+  }
+  return RTCError::OK();
+}
+
 }  // namespace webrtc
diff --git a/webrtc/ortc/rtptransportcontrolleradapter.h b/webrtc/ortc/rtptransportcontrolleradapter.h
index 4e02b95..902ec01 100644
--- a/webrtc/ortc/rtptransportcontrolleradapter.h
+++ b/webrtc/ortc/rtptransportcontrolleradapter.h
@@ -16,18 +16,18 @@
 #include <string>
 #include <vector>
 
+#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
+#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
+#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
+#include "webrtc/api/ortc/srtptransportinterface.h"
 #include "webrtc/base/constructormagic.h"
 #include "webrtc/base/sigslot.h"
 #include "webrtc/base/thread.h"
 #include "webrtc/call/call.h"
 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
-#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
-#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
-#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
-#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/media/base/mediachannel.h"  // For MediaConfig.
 #include "webrtc/pc/channelmanager.h"
 #include "webrtc/pc/mediacontroller.h"
-#include "webrtc/media/base/mediachannel.h"  // For MediaConfig.
 
 namespace webrtc {
 
@@ -81,6 +81,12 @@
       const RtcpParameters& rtcp_parameters,
       PacketTransportInterface* rtp,
       PacketTransportInterface* rtcp);
+
+  RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
+  CreateProxiedSrtpTransport(const RtcpParameters& rtcp_parameters,
+                             PacketTransportInterface* rtp,
+                             PacketTransportInterface* rtcp);
+
   // |transport_proxy| needs to be a proxy to a transport because the
   // application may call GetTransport() on the returned sender or receiver,
   // and expects it to return a thread-safe transport proxy.
@@ -170,6 +176,13 @@
       const std::string& cname,
       const cricket::MediaContentDescription& description) const;
 
+  // If the |rtp_transport| is a SrtpTransport, set the cryptos of the
+  // audio/video content descriptions.
+  RTCError MaybeSetCryptos(
+      RtpTransportInterface* rtp_transport,
+      cricket::MediaContentDescription* local_description,
+      cricket::MediaContentDescription* remote_description);
+
   rtc::Thread* signaling_thread_;
   rtc::Thread* worker_thread_;
   // |transport_proxies_| and |inner_audio_transport_|/|inner_audio_transport_|
diff --git a/webrtc/ortc/srtptransport_unittest.cc b/webrtc/ortc/srtptransport_unittest.cc
new file mode 100644
index 0000000..1287a02
--- /dev/null
+++ b/webrtc/ortc/srtptransport_unittest.cc
@@ -0,0 +1,167 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory>
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/media/base/fakemediaengine.h"
+#include "webrtc/ortc/ortcfactory.h"
+#include "webrtc/ortc/testrtpparameters.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
+
+namespace webrtc {
+
+static const char kTestSha1KeyParams1[] =
+    "inline:WVNfX19zZW1jdGwgKCkgewkyMjA7fQp9CnVubGVz";
+static const char kTestSha1KeyParams2[] =
+    "inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR";
+static const char kTestGcmKeyParams3[] =
+    "inline:e166KFlKzJsGW0d5apX+rrI05vxbrvMJEzFI14aTDCa63IRTlLK4iH66uOI=";
+
+static const cricket::CryptoParams kTestSha1CryptoParams1(
+    1,
+    "AES_CM_128_HMAC_SHA1_80",
+    kTestSha1KeyParams1,
+    "");
+static const cricket::CryptoParams kTestSha1CryptoParams2(
+    1,
+    "AES_CM_128_HMAC_SHA1_80",
+    kTestSha1KeyParams2,
+    "");
+static const cricket::CryptoParams kTestGcmCryptoParams3(1,
+                                                         "AEAD_AES_256_GCM",
+                                                         kTestGcmKeyParams3,
+                                                         "");
+
+// This test uses fake packet transports and a fake media engine, in order to
+// test the SrtpTransport at only an API level. Any end-to-end test should go in
+// ortcfactory_integrationtest.cc instead.
+class SrtpTransportTest : public testing::Test {
+ public:
+  SrtpTransportTest() {
+    fake_media_engine_ = new cricket::FakeMediaEngine();
+    // Note: This doesn't need to use fake network classes, since it uses
+    // FakePacketTransports.
+    auto result = OrtcFactory::Create(
+        nullptr, nullptr, nullptr, nullptr, nullptr,
+        std::unique_ptr<cricket::MediaEngineInterface>(fake_media_engine_));
+    ortc_factory_ = result.MoveValue();
+    rtp_transport_controller_ =
+        ortc_factory_->CreateRtpTransportController().MoveValue();
+
+    fake_packet_transport_.reset(new rtc::FakePacketTransport("fake"));
+    auto srtp_transport_result = ortc_factory_->CreateSrtpTransport(
+        rtcp_parameters_, fake_packet_transport_.get(), nullptr,
+        rtp_transport_controller_.get());
+    srtp_transport_ = srtp_transport_result.MoveValue();
+  }
+
+ protected:
+  // Owned by |ortc_factory_|.
+  cricket::FakeMediaEngine* fake_media_engine_;
+  std::unique_ptr<OrtcFactoryInterface> ortc_factory_;
+  std::unique_ptr<RtpTransportControllerInterface> rtp_transport_controller_;
+  std::unique_ptr<SrtpTransportInterface> srtp_transport_;
+  RtcpParameters rtcp_parameters_;
+  std::unique_ptr<rtc::FakePacketTransport> fake_packet_transport_;
+};
+
+// Tests that setting the SRTP send/receive key succeeds.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKey) {
+  EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+  EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+  auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+                                                      srtp_transport_.get());
+  EXPECT_TRUE(sender_result.ok());
+  auto receiver_result = ortc_factory_->CreateRtpReceiver(
+      cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+  EXPECT_TRUE(receiver_result.ok());
+}
+
+// Tests that setting the SRTP send/receive key twice is not supported.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyTwice) {
+  EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+  EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+            srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams2).type());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+            srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams1).type());
+  // Ensure that the senders and receivers can be created despite the previous
+  // errors.
+  auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+                                                      srtp_transport_.get());
+  EXPECT_TRUE(sender_result.ok());
+  auto receiver_result = ortc_factory_->CreateRtpReceiver(
+      cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+  EXPECT_TRUE(receiver_result.ok());
+}
+
+// Test that the SRTP send key and receive key must have the same cipher suite.
+TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyDifferentCipherSuite) {
+  EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
+            srtp_transport_->SetSrtpReceiveKey(kTestGcmCryptoParams3).type());
+  EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+  // Ensure that the senders and receivers can be created despite the previous
+  // error.
+  auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
+                                                      srtp_transport_.get());
+  EXPECT_TRUE(sender_result.ok());
+  auto receiver_result = ortc_factory_->CreateRtpReceiver(
+      cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
+  EXPECT_TRUE(receiver_result.ok());
+}
+
+class SrtpTransportTestWithMediaType
+    : public SrtpTransportTest,
+      public ::testing::WithParamInterface<cricket::MediaType> {};
+
+// Tests that the senders cannot be created before setting the keys.
+TEST_P(SrtpTransportTestWithMediaType, CreateSenderBeforeSettingKeys) {
+  auto sender_result =
+      ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
+  EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+  sender_result =
+      ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
+  EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+  // Ensure that after the keys are set, a sender can be created, despite the
+  // previous errors.
+  sender_result =
+      ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
+  EXPECT_TRUE(sender_result.ok());
+}
+
+// Tests that the receivers cannot be created before setting the keys.
+TEST_P(SrtpTransportTestWithMediaType, CreateReceiverBeforeSettingKeys) {
+  auto receiver_result =
+      ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
+            receiver_result.error().type());
+  EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
+  receiver_result =
+      ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+  EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
+            receiver_result.error().type());
+  EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
+  // Ensure that after the keys are set, a receiver can be created, despite the
+  // previous errors.
+  receiver_result =
+      ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
+  EXPECT_TRUE(receiver_result.ok());
+}
+
+INSTANTIATE_TEST_CASE_P(SenderCreatationTest,
+                        SrtpTransportTestWithMediaType,
+                        ::testing::Values(cricket::MEDIA_TYPE_AUDIO,
+                                          cricket::MEDIA_TYPE_VIDEO));
+
+}  // namespace webrtc