Introduce SctpOptions struct as argument to SctpTransport::Start

currently containing the SDP-negotiated parameters
- max-message-size
- sctp-port (local and remote)

This deprecates SctpTransportInternal::Start with the individual
parameters. Replace calls to
  Start(local_sctp_port, remote_sctp_port, max_message_size);
with
  Start({
    .local_port = local_sctp_port,
    .remote_port = remote_sctp_port,
    .max_message_size = max_message_size
  });

BUG=webrtc:402429107

Change-Id: I43c60075e28b211bdc95c2040d3cccd0ac96d125
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/380580
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@meta.com>
Cr-Commit-Position: refs/heads/main@{#44130}
diff --git a/api/sctp_transport_interface.h b/api/sctp_transport_interface.h
index 173f3ef..c80fddf 100644
--- a/api/sctp_transport_interface.h
+++ b/api/sctp_transport_interface.h
@@ -88,6 +88,26 @@
   virtual void UnregisterObserver() = 0;
 };
 
+// The size of the SCTP association send buffer. 256kB, the usrsctp default.
+constexpr int kSctpSendBufferSize = 256 * 1024;
+
+// SCTP options negotiated in the SDP.
+struct SctpOptions {
+  // https://www.rfc-editor.org/rfc/rfc8841.html#name-sctp-port
+  // `local_port` and `remote_port` are passed along the wire and the
+  // listener and connector must be using the same port. They are not related
+  // to the ports at the IP level. If set to -1 we default to
+  // kSctpDefaultPort.
+  // TODO(bugs.webrtc.org/402429107): make these optional<uint16_t>.
+  int local_port = -1;
+  int remote_port = -1;
+
+  // https://www.rfc-editor.org/rfc/rfc8841.html#name-max-message-size
+  // `max_message_size` sets the maxium message size on the connection.
+  // It must be smaller than or equal to kSctpSendBufferSize.
+  int max_message_size = kSctpSendBufferSize;
+};
+
 }  // namespace webrtc
 
 #endif  // API_SCTP_TRANSPORT_INTERFACE_H_
diff --git a/media/BUILD.gn b/media/BUILD.gn
index ab9316c..fcca48c 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -712,6 +712,7 @@
   sources = [ "sctp/sctp_transport_internal.h" ]
   deps = [
     ":media_channel",
+    "../api:libjingle_peerconnection_api",
     "../api:priority",
     "../api:rtc_error",
     "../api/transport:datagram_transport_interface",
@@ -1057,6 +1058,7 @@
         "../rtc_base/synchronization:mutex",
         "../rtc_base/system:file_wrapper",
         "../rtc_base/third_party/sigslot",
+        "../system_wrappers",
         "../system_wrappers:field_trial",
         "../test:audio_codec_mocks",
         "../test:fake_video_codecs",
diff --git a/media/sctp/dcsctp_transport.cc b/media/sctp/dcsctp_transport.cc
index 3422b31..e67a266 100644
--- a/media/sctp/dcsctp_transport.cc
+++ b/media/sctp/dcsctp_transport.cc
@@ -28,6 +28,7 @@
 #include "api/environment/environment.h"
 #include "api/priority.h"
 #include "api/rtc_error.h"
+#include "api/sctp_transport_interface.h"
 #include "api/sequence_checker.h"
 #include "api/task_queue/task_queue_base.h"
 #include "api/transport/data_channel_transport_interface.h"
@@ -192,20 +193,18 @@
   MaybeConnectSocket();
 }
 
-bool DcSctpTransport::Start(int local_sctp_port,
-                            int remote_sctp_port,
-                            int max_message_size) {
+bool DcSctpTransport::Start(const SctpOptions& options) {
   RTC_DCHECK_RUN_ON(network_thread_);
-  RTC_DCHECK(max_message_size > 0);
-  RTC_DLOG(LS_INFO) << debug_name_ << "->Start(local=" << local_sctp_port
-                    << ", remote=" << remote_sctp_port
-                    << ", max_message_size=" << max_message_size << ")";
+  RTC_DCHECK(options.max_message_size > 0);
+  RTC_DLOG(LS_INFO) << debug_name_ << "->Start(local=" << options.local_port
+                    << ", remote=" << options.remote_port
+                    << ", max_message_size=" << options.max_message_size << ")";
 
   if (!socket_) {
     dcsctp::DcSctpOptions options;
-    options.local_port = local_sctp_port;
-    options.remote_port = remote_sctp_port;
-    options.max_message_size = max_message_size;
+    options.local_port = options.local_port;
+    options.remote_port = options.remote_port;
+    options.max_message_size = options.max_message_size;
     options.max_timer_backoff_duration = kMaxTimerBackoffDuration;
     // Don't close the connection automatically on too many retransmissions.
     options.max_retransmissions = std::nullopt;
@@ -226,15 +225,15 @@
     socket_ = socket_factory_->Create(debug_name_, *this,
                                       std::move(packet_observer), options);
   } else {
-    if (local_sctp_port != socket_->options().local_port ||
-        remote_sctp_port != socket_->options().remote_port) {
+    if (options.local_port != socket_->options().local_port ||
+        options.remote_port != socket_->options().remote_port) {
       RTC_LOG(LS_ERROR)
-          << debug_name_ << "->Start(local=" << local_sctp_port
-          << ", remote=" << remote_sctp_port
+          << debug_name_ << "->Start(local=" << options.local_port
+          << ", remote=" << options.remote_port
           << "): Can't change ports on already started transport.";
       return false;
     }
-    socket_->SetMaxMessageSize(max_message_size);
+    socket_->SetMaxMessageSize(options.max_message_size);
   }
 
   MaybeConnectSocket();
@@ -722,7 +721,10 @@
     RTC_DLOG(LS_INFO) << debug_name_ << " DTLS restart";
     dcsctp::DcSctpOptions options = socket_->options();
     socket_.reset();
-    Start(options.local_port, options.remote_port, options.max_message_size);
+    RTC_DCHECK_LE(options.max_message_size, kSctpSendBufferSize);
+    Start({.local_port = options.local_port,
+           .remote_port = options.remote_port,
+           .max_message_size = static_cast<int>(options.max_message_size)});
   }
 }
 
diff --git a/media/sctp/dcsctp_transport.h b/media/sctp/dcsctp_transport.h
index f80214b..3d3b1ec 100644
--- a/media/sctp/dcsctp_transport.h
+++ b/media/sctp/dcsctp_transport.h
@@ -11,19 +11,27 @@
 #ifndef MEDIA_SCTP_DCSCTP_TRANSPORT_H_
 #define MEDIA_SCTP_DCSCTP_TRANSPORT_H_
 
+#include <cstddef>
+#include <cstdint>
+#include <functional>
 #include <memory>
 #include <optional>
 #include <string>
 
 #include "absl/strings/string_view.h"
 #include "api/array_view.h"
+#include "api/dtls_transport_interface.h"
 #include "api/environment/environment.h"
 #include "api/priority.h"
+#include "api/rtc_error.h"
+#include "api/sctp_transport_interface.h"
 #include "api/task_queue/task_queue_base.h"
+#include "api/transport/data_channel_transport_interface.h"
 #include "media/sctp/sctp_transport_internal.h"
-#include "net/dcsctp/public/dcsctp_options.h"
+#include "net/dcsctp/public/dcsctp_message.h"
 #include "net/dcsctp/public/dcsctp_socket.h"
 #include "net/dcsctp/public/dcsctp_socket_factory.h"
+#include "net/dcsctp/public/timeout.h"
 #include "net/dcsctp/public/types.h"
 #include "net/dcsctp/timer/task_queue_timeout.h"
 #include "p2p/base/packet_transport_internal.h"
@@ -35,7 +43,6 @@
 #include "rtc_base/third_party/sigslot/sigslot.h"
 #include "rtc_base/thread.h"
 #include "rtc_base/thread_annotations.h"
-#include "system_wrappers/include/clock.h"
 
 namespace webrtc {
 
@@ -56,9 +63,7 @@
   void SetOnConnectedCallback(std::function<void()> callback) override;
   void SetDataChannelSink(DataChannelSink* sink) override;
   void SetDtlsTransport(cricket::DtlsTransportInternal* transport) override;
-  bool Start(int local_sctp_port,
-             int remote_sctp_port,
-             int max_message_size) override;
+  bool Start(const SctpOptions& options) override;
   bool OpenStream(int sid, PriorityValue priority) override;
   bool ResetStream(int sid) override;
   RTCError SendData(int sid,
diff --git a/media/sctp/dcsctp_transport_unittest.cc b/media/sctp/dcsctp_transport_unittest.cc
index a6de226..a609e0f 100644
--- a/media/sctp/dcsctp_transport_unittest.cc
+++ b/media/sctp/dcsctp_transport_unittest.cc
@@ -19,6 +19,7 @@
 #include "api/priority.h"
 #include "api/rtc_error.h"
 #include "api/transport/data_channel_transport_interface.h"
+#include "net/dcsctp/public/dcsctp_message.h"
 #include "net/dcsctp/public/dcsctp_options.h"
 #include "net/dcsctp/public/dcsctp_socket.h"
 #include "net/dcsctp/public/mock_dcsctp_socket.h"
@@ -27,6 +28,7 @@
 #include "p2p/dtls/fake_dtls_transport.h"
 #include "rtc_base/copy_on_write_buffer.h"
 #include "rtc_base/thread.h"
+#include "system_wrappers/include/clock.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
@@ -107,8 +109,9 @@
                        &dcsctp::DcSctpSocketCallbacks::OnConnected));
   EXPECT_CALL(peer_a.sink_, OnReadyToSend);
   EXPECT_CALL(peer_a.sink_, OnConnected);
-
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
 }
 
 // Tests that the close sequence invoked from one end results in the stream to
@@ -138,8 +141,12 @@
     EXPECT_CALL(peer_b.sink_, OnChannelClosed(1));
   }
 
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
-  peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
+  peer_b.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
   peer_b.sctp_transport_->OpenStream(1, kDefaultPriority);
   peer_a.sctp_transport_->ResetStream(1);
@@ -180,8 +187,12 @@
     EXPECT_CALL(peer_b.sink_, OnChannelClosed(1));
   }
 
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
-  peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
+  peer_b.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
   peer_b.sctp_transport_->OpenStream(1, kDefaultPriority);
   peer_a.sctp_transport_->ResetStream(1);
@@ -217,7 +228,9 @@
   EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
 
   peer_a.sctp_transport_->OpenStream(1, PriorityValue(1337));
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
   peer_a.sctp_transport_->OpenStream(2, PriorityValue(3141));
 }
 
@@ -227,7 +240,9 @@
 
   EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
 
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
 
   SendDataParams params;
   rtc::CopyOnWriteBuffer payload;
@@ -242,7 +257,9 @@
   EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
 
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
   peer_a.sctp_transport_->ResetStream(1);
 
   SendDataParams params;
@@ -260,7 +277,9 @@
   EXPECT_CALL(*peer_a.socket_, options()).WillOnce(ReturnPointee(&options));
 
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
 
   SendDataParams params;
   rtc::CopyOnWriteBuffer payload;
@@ -276,7 +295,9 @@
       .Times(1);
 
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
 
   static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
       ->OnMessageReceived(
@@ -290,7 +311,9 @@
   EXPECT_CALL(peer_a.sink_, OnDataReceived(_, _, _)).Times(0);
 
   peer_a.sctp_transport_->OpenStream(1, kDefaultPriority);
-  peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
+  peer_a.sctp_transport_->Start({.local_port = 5000,
+                                 .remote_port = 5000,
+                                 .max_message_size = 256 * 1024});
 
   static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
       ->OnMessageReceived(
diff --git a/media/sctp/sctp_transport_internal.h b/media/sctp/sctp_transport_internal.h
index 24e6fb8..47f62fc 100644
--- a/media/sctp/sctp_transport_internal.h
+++ b/media/sctp/sctp_transport_internal.h
@@ -14,24 +14,21 @@
 // TODO(deadbeef): Move SCTP code out of media/, and make it not depend on
 // anything in media/.
 
-#include <memory>
-#include <string>
-#include <vector>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <optional>
 
 #include "api/priority.h"
 #include "api/rtc_error.h"
+#include "api/sctp_transport_interface.h"
 #include "api/transport/data_channel_transport_interface.h"
-#include "media/base/media_channel.h"
-#include "p2p/base/packet_transport_internal.h"
 #include "p2p/dtls/dtls_transport_internal.h"
 #include "rtc_base/copy_on_write_buffer.h"
-#include "rtc_base/thread.h"
 
 namespace cricket {
 
 // Constants that are important to API users
-// The size of the SCTP association send buffer. 256kB, the usrsctp default.
-constexpr int kSctpSendBufferSize = 256 * 1024;
 
 // The number of outgoing streams that we'll negotiate. Since stream IDs (SIDs)
 // are 0-based, the highest usable SID is 1023.
@@ -91,20 +88,20 @@
   // completes. This method can be called multiple times, though not if either
   // of the ports are changed.
   //
-  // `local_sctp_port` and `remote_sctp_port` are passed along the wire and the
-  // listener and connector must be using the same port. They are not related
-  // to the ports at the IP level. If set to -1, we default to
-  // kSctpDefaultPort.
-  // `max_message_size_` sets the max message size on the connection.
-  // It must be smaller than or equal to kSctpSendBufferSize.
-  // It can be changed by a secons Start() call.
-  //
+  virtual bool Start(const webrtc::SctpOptions& options) = 0;
   // TODO(deadbeef): Support calling Start with different local/remote ports
   // and create a new association? Not clear if this is something we need to
   // support though. See: https://github.com/w3c/webrtc-pc/issues/979
+  [[deprecated("Call with SctpOptions")]]
   virtual bool Start(int local_sctp_port,
                      int remote_sctp_port,
-                     int max_message_size) = 0;
+                     int max_message_size) {
+    return Start({
+        .local_port = local_sctp_port,
+        .remote_port = remote_sctp_port,
+        .max_message_size = max_message_size,
+    });
+  }
 
   // NOTE: Initially there was a "Stop" method here, but it was never used, so
   // it was removed.
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index f147c49..20984d0 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -365,6 +365,7 @@
     ":simulcast_description",
     ":used_ids",
     "../api:field_trials_view",
+    "../api:libjingle_peerconnection_api",
     "../api:rtc_error",
     "../api:rtp_parameters",
     "../api:rtp_transceiver_direction",
diff --git a/pc/media_session.cc b/pc/media_session.cc
index ec5c85c..82722a2 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -27,13 +27,13 @@
 #include "api/rtc_error.h"
 #include "api/rtp_parameters.h"
 #include "api/rtp_transceiver_direction.h"
+#include "api/sctp_transport_interface.h"
 #include "media/base/codec.h"
 #include "media/base/codec_list.h"
 #include "media/base/media_constants.h"
 #include "media/base/media_engine.h"
 #include "media/base/rid_description.h"
 #include "media/base/stream_params.h"
-#include "media/sctp/sctp_transport_internal.h"
 #include "p2p/base/ice_credentials_iterator.h"
 #include "p2p/base/p2p_constants.h"
 #include "p2p/base/transport_description.h"
@@ -1267,7 +1267,7 @@
   data->set_protocol(secure_transport ? kMediaProtocolUdpDtlsSctp
                                       : kMediaProtocolSctp);
   data->set_use_sctpmap(session_options.use_obsolete_sctp_sdp);
-  data->set_max_message_size(kSctpSendBufferSize);
+  data->set_max_message_size(webrtc::kSctpSendBufferSize);
 
   auto error = CreateContentOffer(media_description_options, session_options,
                                   RtpHeaderExtensions(), ssrc_generator(),
@@ -1474,10 +1474,11 @@
     // we do not implement infinite size messages, reply with
     // kSctpSendBufferSize.
     if (offer_data_description->max_message_size() <= 0) {
-      data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
+      data_answer->as_sctp()->set_max_message_size(webrtc::kSctpSendBufferSize);
     } else {
-      data_answer->as_sctp()->set_max_message_size(std::min(
-          offer_data_description->max_message_size(), kSctpSendBufferSize));
+      data_answer->as_sctp()->set_max_message_size(
+          std::min(offer_data_description->max_message_size(),
+                   webrtc::kSctpSendBufferSize));
     }
     if (!CreateMediaContentAnswer(
             offer_data_description, media_description_options, session_options,
diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc
index be8df4a..ab11d66 100644
--- a/pc/media_session_unittest.cc
+++ b/pc/media_session_unittest.cc
@@ -30,6 +30,7 @@
 #include "api/media_types.h"
 #include "api/rtp_parameters.h"
 #include "api/rtp_transceiver_direction.h"
+#include "api/sctp_transport_interface.h"
 #include "api/video_codecs/sdp_video_format.h"
 #include "call/fake_payload_type_suggester.h"
 #include "call/payload_type.h"
@@ -39,7 +40,6 @@
 #include "media/base/rid_description.h"
 #include "media/base/stream_params.h"
 #include "media/base/test_utils.h"
-#include "media/sctp/sctp_transport_internal.h"
 #include "p2p/base/p2p_constants.h"
 #include "p2p/base/transport_description.h"
 #include "p2p/base/transport_description_factory.h"
@@ -1656,7 +1656,7 @@
   const SctpDataContentDescription* dcd_answer =
       dc_answer->media_description()->as_sctp();
   EXPECT_FALSE(dc_answer->rejected);
-  EXPECT_EQ(kSctpSendBufferSize, dcd_answer->max_message_size());
+  EXPECT_EQ(webrtc::kSctpSendBufferSize, dcd_answer->max_message_size());
 }
 
 // Verifies that the order of the media contents in the offer is preserved in
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 90648e2..9f11940 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -2942,20 +2942,17 @@
   return observer_;
 }
 
-void PeerConnection::StartSctpTransport(int local_port,
-                                        int remote_port,
-                                        int max_message_size) {
+void PeerConnection::StartSctpTransport(const SctpOptions& options) {
   RTC_DCHECK_RUN_ON(signaling_thread());
   if (!sctp_mid_s_)
     return;
 
-  network_thread()->PostTask(SafeTask(
-      network_thread_safety_,
-      [this, mid = *sctp_mid_s_, local_port, remote_port, max_message_size] {
+  network_thread()->PostTask(
+      SafeTask(network_thread_safety_, [this, mid = *sctp_mid_s_, options] {
         rtc::scoped_refptr<SctpTransport> sctp_transport =
             transport_controller_n()->GetSctpTransport(mid);
         if (sctp_transport)
-          sctp_transport->Start(local_port, remote_port, max_message_size);
+          sctp_transport->Start(options);
       }));
 }
 
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index 0667f77..39d7b2c 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -412,9 +412,7 @@
 
   // Asynchronously calls SctpTransport::Start() on the network thread for
   // `sctp_mid()` if set. Called as part of setting the local description.
-  void StartSctpTransport(int local_port,
-                          int remote_port,
-                          int max_message_size) override;
+  void StartSctpTransport(const SctpOptions& options) override;
 
   // Returns the CryptoOptions for this PeerConnection. This will always
   // return the RTCConfiguration.crypto_options if set and will only default
diff --git a/pc/peer_connection_internal.h b/pc/peer_connection_internal.h
index 95c4268..ce69fbd 100644
--- a/pc/peer_connection_internal.h
+++ b/pc/peer_connection_internal.h
@@ -31,6 +31,7 @@
 #include "api/rtc_error.h"
 #include "api/rtp_transceiver_interface.h"
 #include "api/scoped_refptr.h"
+#include "api/sctp_transport_interface.h"
 #include "call/call.h"
 #include "call/payload_type_picker.h"
 #include "p2p/base/port.h"
@@ -124,9 +125,15 @@
                  bool fire_callback = true) = 0;
   // Asynchronously calls SctpTransport::Start() on the network thread for
   // `sctp_mid()` if set. Called as part of setting the local description.
+  virtual void StartSctpTransport(const SctpOptions& options) = 0;
+  [[deprecated("Call with SctpOptions")]]
   virtual void StartSctpTransport(int local_port,
                                   int remote_port,
-                                  int max_message_size) = 0;
+                                  int max_message_size) {
+    return StartSctpTransport({.local_port = local_port,
+                               .remote_port = remote_port,
+                               .max_message_size = max_message_size});
+  }
 
   // Asynchronously adds a remote candidate on the network thread.
   virtual void AddRemoteCandidate(absl::string_view mid,
diff --git a/pc/sctp_transport.cc b/pc/sctp_transport.cc
index f26d7ca..78f50ff 100644
--- a/pc/sctp_transport.cc
+++ b/pc/sctp_transport.cc
@@ -11,14 +11,25 @@
 #include "pc/sctp_transport.h"
 
 #include <algorithm>
+#include <cstddef>
+#include <memory>
 #include <optional>
 #include <utility>
 
 #include "api/dtls_transport_interface.h"
 #include "api/priority.h"
+#include "api/rtc_error.h"
+#include "api/scoped_refptr.h"
+#include "api/sctp_transport_interface.h"
 #include "api/sequence_checker.h"
+#include "api/transport/data_channel_transport_interface.h"
+#include "media/sctp/sctp_transport_internal.h"
+#include "p2p/dtls/dtls_transport_internal.h"
+#include "pc/dtls_transport.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/copy_on_write_buffer.h"
 #include "rtc_base/logging.h"
+#include "rtc_base/thread.h"
 
 namespace webrtc {
 
@@ -143,14 +154,13 @@
   UpdateInformation(SctpTransportState::kClosed);
 }
 
-void SctpTransport::Start(int local_port,
-                          int remote_port,
-                          int max_message_size) {
+void SctpTransport::Start(const SctpOptions& options) {
   RTC_DCHECK_RUN_ON(owner_thread_);
-  info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
-                                   max_message_size, info_.MaxChannels());
+  info_ =
+      SctpTransportInformation(info_.state(), info_.dtls_transport(),
+                               options.max_message_size, info_.MaxChannels());
 
-  if (!internal()->Start(local_port, remote_port, max_message_size)) {
+  if (!internal()->Start(options)) {
     RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
     UpdateInformation(SctpTransportState::kClosed);
   }
diff --git a/pc/sctp_transport.h b/pc/sctp_transport.h
index bee64a8..5b7f828 100644
--- a/pc/sctp_transport.h
+++ b/pc/sctp_transport.h
@@ -63,7 +63,7 @@
   void Clear();
   // Initialize the cricket::SctpTransport. This can be called from
   // the signaling thread.
-  void Start(int local_port, int remote_port, int max_message_size);
+  void Start(const SctpOptions& options);
 
   // TODO(https://bugs.webrtc.org/10629): Move functions that need
   // internal() to be functions on the SctpTransport interface,
diff --git a/pc/sctp_transport_unittest.cc b/pc/sctp_transport_unittest.cc
index d17ad54..0631e35 100644
--- a/pc/sctp_transport_unittest.cc
+++ b/pc/sctp_transport_unittest.cc
@@ -53,9 +53,7 @@
   }
   void SetDataChannelSink(DataChannelSink* sink) override {}
   void SetDtlsTransport(cricket::DtlsTransportInternal* transport) override {}
-  bool Start(int local_port, int remote_port, int max_message_size) override {
-    return true;
-  }
+  bool Start(const SctpOptions& options) override { return true; }
   bool OpenStream(int sid, PriorityValue priority) override { return true; }
   bool ResetStream(int sid) override { return true; }
   RTCError SendData(int sid,
diff --git a/pc/sdp_offer_answer.cc b/pc/sdp_offer_answer.cc
index cb896c9..96a1cb9 100644
--- a/pc/sdp_offer_answer.cc
+++ b/pc/sdp_offer_answer.cc
@@ -5056,9 +5056,9 @@
             std::min(local_sctp_description->max_message_size(),
                      remote_sctp_description->max_message_size());
       }
-      pc_->StartSctpTransport(local_sctp_description->port(),
-                              remote_sctp_description->port(),
-                              max_message_size);
+      pc_->StartSctpTransport({.local_port = local_sctp_description->port(),
+                               .remote_port = remote_sctp_description->port(),
+                               .max_message_size = max_message_size});
     }
   }
 
diff --git a/pc/test/fake_peer_connection_base.h b/pc/test/fake_peer_connection_base.h
index 2022b04..0138dca 100644
--- a/pc/test/fake_peer_connection_base.h
+++ b/pc/test/fake_peer_connection_base.h
@@ -389,9 +389,7 @@
       bool fire_callback = true) override {
     return RTCError(RTCErrorType::INTERNAL_ERROR, "");
   }
-  void StartSctpTransport(int local_port,
-                          int remote_port,
-                          int max_message_size) override {}
+  void StartSctpTransport(const SctpOptions& options) override {}
 
   void AddRemoteCandidate(absl::string_view mid,
                           const cricket::Candidate& candidate) override {}
diff --git a/pc/test/mock_peer_connection_internal.h b/pc/test/mock_peer_connection_internal.h
index 785510f..25d9d82 100644
--- a/pc/test/mock_peer_connection_internal.h
+++ b/pc/test/mock_peer_connection_internal.h
@@ -309,7 +309,7 @@
                const RtpTransceiverInit&,
                bool),
               (override));
-  MOCK_METHOD(void, StartSctpTransport, (int, int, int), (override));
+  MOCK_METHOD(void, StartSctpTransport, (const SctpOptions&), (override));
   MOCK_METHOD(void,
               AddRemoteCandidate,
               (absl::string_view, const cricket::Candidate&),
diff --git a/test/pc/sctp/BUILD.gn b/test/pc/sctp/BUILD.gn
index 24004d6..e30fd82 100644
--- a/test/pc/sctp/BUILD.gn
+++ b/test/pc/sctp/BUILD.gn
@@ -12,9 +12,14 @@
   visibility = [ "*" ]
   sources = [ "fake_sctp_transport.h" ]
   deps = [
+    "../../../api:libjingle_peerconnection_api",
     "../../../api:priority",
+    "../../../api:rtc_error",
     "../../../api/environment",
+    "../../../api/transport:datagram_transport_interface",
     "../../../api/transport:sctp_transport_factory_interface",
     "../../../media:rtc_data_sctp_transport_internal",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:copy_on_write_buffer",
   ]
 }
diff --git a/test/pc/sctp/fake_sctp_transport.h b/test/pc/sctp/fake_sctp_transport.h
index 3f71d44..a22460f 100644
--- a/test/pc/sctp/fake_sctp_transport.h
+++ b/test/pc/sctp/fake_sctp_transport.h
@@ -11,12 +11,20 @@
 #ifndef TEST_PC_SCTP_FAKE_SCTP_TRANSPORT_H_
 #define TEST_PC_SCTP_FAKE_SCTP_TRANSPORT_H_
 
+#include <cstddef>
+#include <functional>
 #include <memory>
+#include <optional>
 
 #include "api/environment/environment.h"
 #include "api/priority.h"
+#include "api/rtc_error.h"
+#include "api/sctp_transport_interface.h"
+#include "api/transport/data_channel_transport_interface.h"
 #include "api/transport/sctp_transport_factory_interface.h"
 #include "media/sctp/sctp_transport_internal.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/copy_on_write_buffer.h"
 
 // Used for tests in this file to verify that PeerConnection responds to signals
 // from the SctpTransport correctly, and calls Start with the correct
@@ -26,10 +34,10 @@
   void SetOnConnectedCallback(std::function<void()> callback) override {}
   void SetDataChannelSink(webrtc::DataChannelSink* sink) override {}
   void SetDtlsTransport(cricket::DtlsTransportInternal* transport) override {}
-  bool Start(int local_port, int remote_port, int max_message_size) override {
-    local_port_.emplace(local_port);
-    remote_port_.emplace(remote_port);
-    max_message_size_ = max_message_size;
+  bool Start(const webrtc::SctpOptions& options) override {
+    local_port_.emplace(options.local_port);
+    remote_port_.emplace(options.remote_port);
+    max_message_size_ = options.max_message_size;
     return true;
   }
   bool OpenStream(int sid, webrtc::PriorityValue priority) override {