Integration of media_transport in JSepTransportController

Basic integration of media_transport in JSepTransportController.

- Creates media_transport if media transport factory provided in jsep transport controller configuration.
- Unittest that makes sure media_transport is created with correct caller or callee setting.
- Added fake_media_transport, for now simple implementation which only stores caller/callee, but in the future fake media transport will be expanded to pass frames between two fake media_transports, which will enable audio / video integration tests.

NEXT STEPS: Once integration of media_transport with PeerConnection (https://webrtc-review.googlesource.com/c/src/+/103860) lands, we can start passing media transport factory from peer connection to jsep transport controller.

NOTE: Includes missing include change from https://webrtc-review.googlesource.com/c/src/+/103540 (otherwise this change will not compile)

Bug: webrtc:9719
Change-Id: I1e8a521beab445aa9f7ea93c8d7a537dc137d11c
Reviewed-on: https://webrtc-review.googlesource.com/c/104400
Commit-Queue: Anton Sukhanov <sukhanov@google.com>
Reviewed-by: Peter Slatala <psla@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25096}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 5fdebc9..60eb751 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -542,4 +542,17 @@
       "units:units_unittests",
     ]
   }
+
+  rtc_source_set("fake_media_transport") {
+    testonly = true
+
+    sources = [
+      "test/fake_media_transport.h",
+    ]
+
+    deps = [
+      ":libjingle_peerconnection_api",
+      "../rtc_base:checks",
+    ]
+  }
 }
diff --git a/api/test/fake_media_transport.h b/api/test/fake_media_transport.h
new file mode 100644
index 0000000..48970a5
--- /dev/null
+++ b/api/test/fake_media_transport.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2018 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 API_TEST_FAKE_MEDIA_TRANSPORT_H_
+#define API_TEST_FAKE_MEDIA_TRANSPORT_H_
+
+#include <memory>
+#include <utility>
+
+#include "api/media_transport_interface.h"
+
+namespace webrtc {
+
+// TODO(sukhanov): For now fake media transport does nothing and is used only
+// in jsepcontroller unittests. In the future we should implement fake media
+// transport, which forwards frames to another fake media transport, so we
+// could unit test audio / video integration.
+class FakeMediaTransport : public MediaTransportInterface {
+ public:
+  explicit FakeMediaTransport(bool is_caller) : is_caller_(is_caller) {}
+  ~FakeMediaTransport() = default;
+
+  RTCError SendAudioFrame(uint64_t channel_id,
+                          MediaTransportEncodedAudioFrame frame) override {
+    return RTCError::OK();
+  }
+
+  RTCError SendVideoFrame(
+      uint64_t channel_id,
+      const MediaTransportEncodedVideoFrame& frame) override {
+    return RTCError::OK();
+  }
+
+  RTCError RequestKeyFrame(uint64_t channel_id) override {
+    return RTCError::OK();
+  };
+
+  void SetReceiveAudioSink(MediaTransportAudioSinkInterface* sink) override {}
+  void SetReceiveVideoSink(MediaTransportVideoSinkInterface* sink) override {}
+
+  // Returns true if fake media trasport was created as a caller.
+  bool is_caller() const { return is_caller_; }
+
+ private:
+  const bool is_caller_;
+};
+
+// Fake media transport factory creates fake media transport.
+class FakeMediaTransportFactory : public MediaTransportFactory {
+ public:
+  FakeMediaTransportFactory() = default;
+  ~FakeMediaTransportFactory() = default;
+
+  RTCErrorOr<std::unique_ptr<MediaTransportInterface>> CreateMediaTransport(
+      rtc::PacketTransportInternal* packet_transport,
+      rtc::Thread* network_thread,
+      bool is_caller) override {
+    RTC_CHECK(network_thread != nullptr);
+    RTC_CHECK(packet_transport != nullptr);
+
+    std::unique_ptr<MediaTransportInterface> media_transport =
+        absl::make_unique<FakeMediaTransport>(is_caller);
+
+    return std::move(media_transport);
+  }
+};
+
+}  // namespace webrtc
+
+#endif  // API_TEST_FAKE_MEDIA_TRANSPORT_H_
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 4e6e558..b6e9c66 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -316,6 +316,7 @@
       ":rtc_pc",
       ":rtc_pc_base",
       "../api:array_view",
+      "../api:fake_media_transport",
       "../api:libjingle_peerconnection_api",
       "../call:rtp_interfaces",
       "../logging:rtc_event_log_api",
diff --git a/pc/jseptransport.cc b/pc/jseptransport.cc
index c3dfd32..894dce1 100644
--- a/pc/jseptransport.cc
+++ b/pc/jseptransport.cc
@@ -13,7 +13,6 @@
 #include <memory>
 #include <utility>  // for std::pair
 
-#include "absl/memory/memory.h"
 #include "api/candidate.h"
 #include "p2p/base/p2pconstants.h"
 #include "p2p/base/p2ptransportchannel.h"
@@ -94,11 +93,13 @@
     std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
     std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
     std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
-    std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport)
+    std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
+    std::unique_ptr<webrtc::MediaTransportInterface> media_transport)
     : mid_(mid),
       local_certificate_(local_certificate),
       rtp_dtls_transport_(std::move(rtp_dtls_transport)),
-      rtcp_dtls_transport_(std::move(rtcp_dtls_transport)) {
+      rtcp_dtls_transport_(std::move(rtcp_dtls_transport)),
+      media_transport_(std::move(media_transport)) {
   RTC_DCHECK(rtp_dtls_transport_);
   if (unencrypted_rtp_transport) {
     RTC_DCHECK(!sdes_transport);
diff --git a/pc/jseptransport.h b/pc/jseptransport.h
index 8e89853..8883218 100644
--- a/pc/jseptransport.h
+++ b/pc/jseptransport.h
@@ -19,6 +19,7 @@
 #include "absl/types/optional.h"
 #include "api/candidate.h"
 #include "api/jsep.h"
+#include "api/media_transport_interface.h"
 #include "p2p/base/dtlstransport.h"
 #include "p2p/base/p2pconstants.h"
 #include "p2p/base/transportinfo.h"
@@ -75,6 +76,10 @@
   // |mid| is just used for log statements in order to identify the Transport.
   // Note that |local_certificate| is allowed to be null since a remote
   // description may be set before a local certificate is generated.
+  //
+  // |media_trasport| is optional (experimental). If available it will be used
+  // to send / receive encoded audio and video frames instead of RTP.
+  // Currently |media_transport| can co-exist with RTP / RTCP transports.
   JsepTransport(
       const std::string& mid,
       const rtc::scoped_refptr<rtc::RTCCertificate>& local_certificate,
@@ -82,7 +87,8 @@
       std::unique_ptr<webrtc::SrtpTransport> sdes_transport,
       std::unique_ptr<webrtc::DtlsSrtpTransport> dtls_srtp_transport,
       std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport,
-      std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport);
+      std::unique_ptr<DtlsTransportInternal> rtcp_dtls_transport,
+      std::unique_ptr<webrtc::MediaTransportInterface> media_transport);
 
   ~JsepTransport() override;
 
@@ -158,6 +164,13 @@
     return rtcp_dtls_transport_.get();
   }
 
+  // Returns media transport, if available.
+  // Note that media transport is owned by jseptransport and the pointer
+  // to media transport will becomes invalid after destruction of jseptransport.
+  webrtc::MediaTransportInterface* media_transport() const {
+    return media_transport_.get();
+  }
+
   // This is signaled when RTCP-mux becomes active and
   // |rtcp_dtls_transport_| is destroyed. The JsepTransportController will
   // handle the signal and update the aggregate transport states.
@@ -241,6 +254,9 @@
   absl::optional<std::vector<int>> send_extension_ids_;
   absl::optional<std::vector<int>> recv_extension_ids_;
 
+  // Optional media transport (experimental).
+  std::unique_ptr<webrtc::MediaTransportInterface> media_transport_;
+
   RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport);
 };
 
diff --git a/pc/jseptransport_unittest.cc b/pc/jseptransport_unittest.cc
index 56a742c..1b42578 100644
--- a/pc/jseptransport_unittest.cc
+++ b/pc/jseptransport_unittest.cc
@@ -98,11 +98,16 @@
         RTC_NOTREACHED();
     }
 
+    // TODO(sukhanov): Currently there is no media_transport specific
+    // logic in jseptransport, so jseptransport unittests are created with
+    // media_transport = nullptr. In the future we will probably add
+    // more logic that require unit tests. Note that creation of media_transport
+    // is covered in jseptransportcontroller_unittest.
     auto jsep_transport = absl::make_unique<JsepTransport>(
         kTransportName, /*local_certificate=*/nullptr,
         std::move(unencrypted_rtp_transport), std::move(sdes_transport),
         std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
-        std::move(rtcp_dtls_transport));
+        std::move(rtcp_dtls_transport), /*media_transport=*/nullptr);
 
     signal_rtcp_mux_active_received_ = false;
     jsep_transport->SignalRtcpMuxActive.connect(
diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc
index 4c69a6a..1847d95 100644
--- a/pc/jseptransportcontroller.cc
+++ b/pc/jseptransportcontroller.cc
@@ -14,7 +14,6 @@
 #include <memory>
 #include <utility>
 
-#include "absl/memory/memory.h"
 #include "p2p/base/port.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/checks.h"
@@ -133,6 +132,15 @@
   return jsep_transport->rtp_transport();
 }
 
+MediaTransportInterface* JsepTransportController::GetMediaTransport(
+    const std::string& mid) const {
+  auto jsep_transport = GetJsepTransportForMid(mid);
+  if (!jsep_transport) {
+    return nullptr;
+  }
+  return jsep_transport->media_transport();
+}
+
 cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
     const std::string& mid) const {
   auto jsep_transport = GetJsepTransportForMid(mid);
@@ -523,7 +531,7 @@
         (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
       continue;
     }
-    error = MaybeCreateJsepTransport(content_info);
+    error = MaybeCreateJsepTransport(local, content_info);
     if (!error.ok()) {
       return error;
     }
@@ -889,6 +897,7 @@
 }
 
 RTCError JsepTransportController::MaybeCreateJsepTransport(
+    bool local,
     const cricket::ContentInfo& content_info) {
   RTC_DCHECK(network_thread_->IsCurrent());
   cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
@@ -906,7 +915,13 @@
 
   std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
       CreateDtlsTransport(content_info.name, /*rtcp =*/false);
+
   std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
+  std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
+  std::unique_ptr<SrtpTransport> sdes_transport;
+  std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
+  std::unique_ptr<MediaTransportInterface> media_transport;
+
   if (config_.rtcp_mux_policy !=
           PeerConnectionInterface::kRtcpMuxPolicyRequire &&
       content_info.type == cricket::MediaProtocolType::kRtp) {
@@ -914,9 +929,20 @@
         CreateDtlsTransport(content_info.name, /*rtcp =*/true);
   }
 
-  std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
-  std::unique_ptr<SrtpTransport> sdes_transport;
-  std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
+  if (config_.media_transport_factory != nullptr) {
+    auto media_transport_result =
+        config_.media_transport_factory->CreateMediaTransport(
+            rtp_dtls_transport->ice_transport(), network_thread_,
+            /*is_caller=*/local);
+
+    // TODO(sukhanov): Proper error handling.
+    RTC_CHECK(media_transport_result.ok());
+
+    media_transport = std::move(media_transport_result.value());
+  }
+
+  // TODO(sukhanov): Do not create RTP/RTCP transports if media transport is
+  // used.
   if (config_.disable_encryption) {
     unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
         content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
@@ -932,7 +958,8 @@
       absl::make_unique<cricket::JsepTransport>(
           content_info.name, certificate_, std::move(unencrypted_rtp_transport),
           std::move(sdes_transport), std::move(dtls_srtp_transport),
-          std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport));
+          std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
+          std::move(media_transport));
   jsep_transport->SignalRtcpMuxActive.connect(
       this, &JsepTransportController::UpdateAggregateStates_n);
   SetTransportForMid(content_info.name, jsep_transport.get());
diff --git a/pc/jseptransportcontroller.h b/pc/jseptransportcontroller.h
index d9340cf..bca4481 100644
--- a/pc/jseptransportcontroller.h
+++ b/pc/jseptransportcontroller.h
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "api/candidate.h"
+#include "api/media_transport_interface.h"
 #include "api/peerconnectioninterface.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
 #include "media/sctp/sctptransportinternal.h"
@@ -79,6 +80,13 @@
     Observer* transport_observer = nullptr;
     bool active_reset_srtp_params = false;
     RtcEventLog* event_log = nullptr;
+
+    // Optional media transport factory (experimental). If provided it will be
+    // used to create media_transport and will be used to send / receive
+    // audio and video frames instead of RTP. Note that currently
+    // media_transport co-exists with RTP / RTCP transports and uses the same
+    // underlying ICE transport.
+    MediaTransportFactory* media_transport_factory = nullptr;
   };
 
   // The ICE related events are signaled on the |signaling_thread|.
@@ -108,6 +116,8 @@
   cricket::DtlsTransportInternal* GetRtcpDtlsTransport(
       const std::string& mid) const;
 
+  MediaTransportInterface* GetMediaTransport(const std::string& mid) const;
+
   /*********************
    * ICE-related methods
    ********************/
@@ -241,7 +251,12 @@
   cricket::JsepTransport* GetJsepTransportByName(
       const std::string& transport_name);
 
-  RTCError MaybeCreateJsepTransport(const cricket::ContentInfo& content_info);
+  // Creates jsep transport. Noop if transport is already created.
+  // Transport is created either during SetLocalDescription (|local| == true) or
+  // during SetRemoteDescription (|local| == false). Passing |local| helps to
+  // differentiate initiator (caller) from answerer (callee).
+  RTCError MaybeCreateJsepTransport(bool local,
+                                    const cricket::ContentInfo& content_info);
   void MaybeDestroyJsepTransport(const std::string& mid);
   void DestroyAllJsepTransports_n();
 
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index 6f8693b..ce431c3 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -11,7 +11,7 @@
 #include <map>
 #include <memory>
 
-#include "absl/memory/memory.h"
+#include "api/test/fake_media_transport.h"
 #include "p2p/base/fakedtlstransport.h"
 #include "p2p/base/fakeicetransport.h"
 #include "p2p/base/transportfactoryinterface.h"
@@ -341,6 +341,55 @@
   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kAudioMid1));
   EXPECT_NE(nullptr, transport_controller_->GetDtlsTransport(kVideoMid1));
   EXPECT_EQ(nullptr, transport_controller_->GetRtcpDtlsTransport(kVideoMid1));
+  EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kAudioMid1));
+}
+
+TEST_F(JsepTransportControllerTest, GetMediaTransportInCaller) {
+  FakeMediaTransportFactory fake_media_transport_factory;
+  JsepTransportController::Config config;
+
+  config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
+  config.media_transport_factory = &fake_media_transport_factory;
+  CreateJsepTransportController(config);
+  auto description = CreateSessionDescriptionWithoutBundle();
+  EXPECT_TRUE(transport_controller_
+                  ->SetLocalDescription(SdpType::kOffer, description.get())
+                  .ok());
+
+  FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
+      transport_controller_->GetMediaTransport(kAudioMid1));
+
+  ASSERT_NE(nullptr, media_transport);
+
+  // After SetLocalDescription, media transport should be created as caller.
+  EXPECT_TRUE(media_transport->is_caller());
+
+  // Return nullptr for non-existing mids.
+  EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
+}
+
+TEST_F(JsepTransportControllerTest, GetMediaTransportInCallee) {
+  FakeMediaTransportFactory fake_media_transport_factory;
+  JsepTransportController::Config config;
+
+  config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
+  config.media_transport_factory = &fake_media_transport_factory;
+  CreateJsepTransportController(config);
+  auto description = CreateSessionDescriptionWithoutBundle();
+  EXPECT_TRUE(transport_controller_
+                  ->SetRemoteDescription(SdpType::kOffer, description.get())
+                  .ok());
+
+  FakeMediaTransport* media_transport = static_cast<FakeMediaTransport*>(
+      transport_controller_->GetMediaTransport(kAudioMid1));
+
+  ASSERT_NE(nullptr, media_transport);
+
+  // After SetRemoteDescription, media transport should be created as callee.
+  EXPECT_FALSE(media_transport->is_caller());
+
+  // Return nullptr for non-existing mids.
+  EXPECT_EQ(nullptr, transport_controller_->GetMediaTransport(kVideoMid2));
 }
 
 TEST_F(JsepTransportControllerTest, SetIceConfig) {