Allow receive-only use of datagram transport for data channels.
Adds a field trial and configuration parameter to control whether datagram transport may be used for data channels in a receive-only manner. By default, if use_datagram_transport_for_data_channels is enabled, PeerConnection will create a datagram transport and offer its use for outgoing calls as well as accept incoming offers with compatible datagram transport parameters. With this change, a receive_only mode is added for datagram transport data channels. When receive_only is set, the PeerConnection will not create or offer datagram transports for outgoing calls, but will accept incoming calls that offer compatible datagram transport parameters. Bug: webrtc:9719 Change-Id: I35667bcc408ea4bbc61155898e6d2472dd262711 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/154463 Reviewed-by: Seth Hampson <shampson@webrtc.org> Commit-Queue: Bjorn Mellem <mellem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29327}
This commit is contained in:
parent
63173d5bef
commit
7da4e563b7
@ -632,6 +632,14 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
|
||||
// of SCTP-DTLS.
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels;
|
||||
|
||||
// If true, this PeerConnection will only use datagram transport for data
|
||||
// channels when receiving an incoming offer that includes datagram
|
||||
// transport parameters. It will not request use of a datagram transport
|
||||
// when it creates the initial, outgoing offer.
|
||||
// This setting only applies when |use_datagram_transport_for_data_channels|
|
||||
// is true.
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels_receive_only;
|
||||
|
||||
// Defines advanced optional cryptographic settings related to SRTP and
|
||||
// frame encryption for native WebRTC. Setting this will overwrite any
|
||||
// settings set in PeerConnectionFactory (which is deprecated).
|
||||
|
||||
@ -447,7 +447,8 @@ void JsepTransportController::SetMediaTransportSettings(
|
||||
bool use_media_transport_for_media,
|
||||
bool use_media_transport_for_data_channels,
|
||||
bool use_datagram_transport,
|
||||
bool use_datagram_transport_for_data_channels) {
|
||||
bool use_datagram_transport_for_data_channels,
|
||||
bool use_datagram_transport_for_data_channels_receive_only) {
|
||||
RTC_DCHECK(use_media_transport_for_media ==
|
||||
config_.use_media_transport_for_media ||
|
||||
jsep_transports_by_name_.empty())
|
||||
@ -466,6 +467,8 @@ void JsepTransportController::SetMediaTransportSettings(
|
||||
config_.use_datagram_transport = use_datagram_transport;
|
||||
config_.use_datagram_transport_for_data_channels =
|
||||
use_datagram_transport_for_data_channels;
|
||||
config_.use_datagram_transport_for_data_channels_receive_only =
|
||||
use_datagram_transport_for_data_channels_receive_only;
|
||||
}
|
||||
|
||||
std::unique_ptr<cricket::IceTransportInternal>
|
||||
@ -1795,6 +1798,10 @@ JsepTransportController::GetTransportParameters(const std::string& mid) {
|
||||
RTC_DCHECK(!local_desc_ && !remote_desc_)
|
||||
<< "JsepTransport should exist for every mid once any description is set";
|
||||
|
||||
if (config_.use_datagram_transport_for_data_channels_receive_only) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Need to generate a transport for the offer.
|
||||
if (!offer_datagram_transport_) {
|
||||
webrtc::MediaTransportSettings settings;
|
||||
|
||||
@ -120,6 +120,11 @@ class JsepTransportController : public sigslot::has_slots<> {
|
||||
// Use datagram transport's implementation of data channels instead of SCTP.
|
||||
bool use_datagram_transport_for_data_channels = false;
|
||||
|
||||
// Whether |use_datagram_transport_for_data_channels| applies to outgoing
|
||||
// calls. If true, |use_datagram_transport_for_data_channels| applies only
|
||||
// to incoming calls.
|
||||
bool use_datagram_transport_for_data_channels_receive_only = false;
|
||||
|
||||
// Optional media transport factory (experimental). If provided it will be
|
||||
// used to create media_transport (as long as either
|
||||
// |use_media_transport_for_media| or
|
||||
@ -227,10 +232,12 @@ class JsepTransportController : public sigslot::has_slots<> {
|
||||
// media transport configuration on the jsep transport controller, as long as
|
||||
// you did not call 'GetMediaTransport' or 'MaybeCreateJsepTransport'. Once
|
||||
// Jsep transport is created, you can't change this setting.
|
||||
void SetMediaTransportSettings(bool use_media_transport_for_media,
|
||||
bool use_media_transport_for_data_channels,
|
||||
bool use_datagram_transport,
|
||||
bool use_datagram_transport_for_data_channels);
|
||||
void SetMediaTransportSettings(
|
||||
bool use_media_transport_for_media,
|
||||
bool use_media_transport_for_data_channels,
|
||||
bool use_datagram_transport,
|
||||
bool use_datagram_transport_for_data_channels,
|
||||
bool use_datagram_transport_for_data_channels_receive_only);
|
||||
|
||||
// If media transport is present enabled and supported,
|
||||
// when this method is called, it creates a media transport and generates its
|
||||
|
||||
@ -778,6 +778,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
bool use_media_transport_for_data_channels;
|
||||
absl::optional<bool> use_datagram_transport;
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels;
|
||||
absl::optional<bool> use_datagram_transport_for_data_channels_receive_only;
|
||||
absl::optional<CryptoOptions> crypto_options;
|
||||
bool offer_extmap_allow_mixed;
|
||||
std::string turn_logging_id;
|
||||
@ -842,6 +843,8 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
use_datagram_transport == o.use_datagram_transport &&
|
||||
use_datagram_transport_for_data_channels ==
|
||||
o.use_datagram_transport_for_data_channels &&
|
||||
use_datagram_transport_for_data_channels_receive_only ==
|
||||
o.use_datagram_transport_for_data_channels_receive_only &&
|
||||
crypto_options == o.crypto_options &&
|
||||
offer_extmap_allow_mixed == o.offer_extmap_allow_mixed &&
|
||||
turn_logging_id == o.turn_logging_id;
|
||||
@ -1080,6 +1083,9 @@ bool PeerConnection::Initialize(
|
||||
datagram_transport_data_channel_config_.enabled &&
|
||||
configuration.use_datagram_transport_for_data_channels.value_or(
|
||||
datagram_transport_data_channel_config_.default_value);
|
||||
use_datagram_transport_for_data_channels_receive_only_ =
|
||||
configuration.use_datagram_transport_for_data_channels_receive_only
|
||||
.value_or(datagram_transport_data_channel_config_.receive_only);
|
||||
if (use_datagram_transport_ || use_datagram_transport_for_data_channels_ ||
|
||||
configuration.use_media_transport ||
|
||||
configuration.use_media_transport_for_data_channels) {
|
||||
@ -1114,6 +1120,8 @@ bool PeerConnection::Initialize(
|
||||
config.use_datagram_transport = use_datagram_transport_;
|
||||
config.use_datagram_transport_for_data_channels =
|
||||
use_datagram_transport_for_data_channels_;
|
||||
config.use_datagram_transport_for_data_channels_receive_only =
|
||||
use_datagram_transport_for_data_channels_receive_only_;
|
||||
config.media_transport_factory = factory_->media_transport_factory();
|
||||
}
|
||||
|
||||
@ -3573,6 +3581,26 @@ RTCError PeerConnection::SetConfiguration(
|
||||
"after calling SetRemoteDescription.");
|
||||
}
|
||||
|
||||
if (local_description() &&
|
||||
configuration.use_datagram_transport_for_data_channels_receive_only !=
|
||||
configuration_
|
||||
.use_datagram_transport_for_data_channels_receive_only) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Can't change use_datagram_transport_for_data_channels_receive_only "
|
||||
"after calling SetLocalDescription.");
|
||||
}
|
||||
|
||||
if (remote_description() &&
|
||||
configuration.use_datagram_transport_for_data_channels_receive_only !=
|
||||
configuration_
|
||||
.use_datagram_transport_for_data_channels_receive_only) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
RTCErrorType::INVALID_MODIFICATION,
|
||||
"Can't change use_datagram_transport_for_data_channels_receive_only "
|
||||
"after calling SetRemoteDescription.");
|
||||
}
|
||||
|
||||
if (configuration.use_media_transport_for_data_channels ||
|
||||
configuration.use_media_transport ||
|
||||
(configuration.use_datagram_transport &&
|
||||
@ -3616,6 +3644,8 @@ RTCError PeerConnection::SetConfiguration(
|
||||
modified_config.use_datagram_transport = configuration.use_datagram_transport;
|
||||
modified_config.use_datagram_transport_for_data_channels =
|
||||
configuration.use_datagram_transport_for_data_channels;
|
||||
modified_config.use_datagram_transport_for_data_channels_receive_only =
|
||||
configuration.use_datagram_transport_for_data_channels_receive_only;
|
||||
modified_config.turn_logging_id = configuration.turn_logging_id;
|
||||
if (configuration != modified_config) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
|
||||
@ -3688,10 +3718,14 @@ RTCError PeerConnection::SetConfiguration(
|
||||
datagram_transport_data_channel_config_.enabled &&
|
||||
modified_config.use_datagram_transport_for_data_channels.value_or(
|
||||
datagram_transport_data_channel_config_.default_value);
|
||||
use_datagram_transport_for_data_channels_receive_only_ =
|
||||
modified_config.use_datagram_transport_for_data_channels_receive_only
|
||||
.value_or(datagram_transport_data_channel_config_.receive_only);
|
||||
transport_controller_->SetMediaTransportSettings(
|
||||
modified_config.use_media_transport,
|
||||
modified_config.use_media_transport_for_data_channels,
|
||||
use_datagram_transport_, use_datagram_transport_for_data_channels_);
|
||||
use_datagram_transport_, use_datagram_transport_for_data_channels_,
|
||||
use_datagram_transport_for_data_channels_receive_only_);
|
||||
|
||||
if (configuration_.active_reset_srtp_params !=
|
||||
modified_config.active_reset_srtp_params) {
|
||||
|
||||
@ -365,8 +365,10 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
// Field-trial based configuration for datagram transport data channels.
|
||||
struct DatagramTransportDataChannelConfig {
|
||||
explicit DatagramTransportDataChannelConfig(const std::string& field_trial)
|
||||
: enabled("enabled", true), default_value("default_value", false) {
|
||||
ParseFieldTrial({&enabled, &default_value}, field_trial);
|
||||
: enabled("enabled", true),
|
||||
default_value("default_value", false),
|
||||
receive_only("receive_only", false) {
|
||||
ParseFieldTrial({&enabled, &default_value, &receive_only}, field_trial);
|
||||
}
|
||||
|
||||
// Whether datagram transport data channel support is enabled at all.
|
||||
@ -382,6 +384,11 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
// applications will use the datagram transport by default (but may still
|
||||
// explicitly configure themselves not to use it through RTCConfiguration).
|
||||
FieldTrialFlag default_value;
|
||||
|
||||
// Whether the datagram transport is enabled in receive-only mode. If true,
|
||||
// and if the datagram transport is enabled, it will only be used when
|
||||
// receiving incoming calls, not when placing outgoing calls.
|
||||
FieldTrialFlag receive_only;
|
||||
};
|
||||
|
||||
// Implements MessageHandler.
|
||||
@ -1196,7 +1203,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
const DatagramTransportConfig datagram_transport_config_;
|
||||
|
||||
// Field-trial based configuration for datagram transport data channels.
|
||||
const DatagramTransportConfig datagram_transport_data_channel_config_;
|
||||
const DatagramTransportDataChannelConfig
|
||||
datagram_transport_data_channel_config_;
|
||||
|
||||
// Final, resolved value for whether datagram transport is in use.
|
||||
bool use_datagram_transport_ RTC_GUARDED_BY(signaling_thread()) = false;
|
||||
@ -1206,6 +1214,10 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
bool use_datagram_transport_for_data_channels_
|
||||
RTC_GUARDED_BY(signaling_thread()) = false;
|
||||
|
||||
// Resolved value of whether to use data channels only for incoming calls.
|
||||
bool use_datagram_transport_for_data_channels_receive_only_
|
||||
RTC_GUARDED_BY(signaling_thread()) = false;
|
||||
|
||||
// Cache configuration_.use_media_transport so that we can access it from
|
||||
// other threads.
|
||||
// TODO(bugs.webrtc.org/9987): Caching just this bool and allowing the data
|
||||
|
||||
@ -3647,8 +3647,101 @@ TEST_P(PeerConnectionIntegrationTest,
|
||||
ASSERT_TRUE(ExpectNewFrames(media_expectations));
|
||||
}
|
||||
|
||||
// Tests that data channels use SCTP instead of datagram transport if datagram
|
||||
// transport is configured in receive-only mode on the caller.
|
||||
TEST_P(PeerConnectionIntegrationTest,
|
||||
DatagramTransportDataChannelReceiveOnlyOnCallerUsesSctp) {
|
||||
PeerConnectionInterface::RTCConfiguration rtc_config;
|
||||
rtc_config.rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire;
|
||||
rtc_config.bundle_policy = PeerConnectionInterface::kBundlePolicyMaxBundle;
|
||||
rtc_config.use_datagram_transport_for_data_channels = true;
|
||||
rtc_config.use_datagram_transport_for_data_channels_receive_only = true;
|
||||
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfigAndMediaTransportFactory(
|
||||
rtc_config, rtc_config, loopback_media_transports()->first_factory(),
|
||||
loopback_media_transports()->second_factory()));
|
||||
ConnectFakeSignaling();
|
||||
|
||||
// The caller should offer a data channel using SCTP.
|
||||
caller()->CreateDataChannel();
|
||||
caller()->AddAudioVideoTracks();
|
||||
callee()->AddAudioVideoTracks();
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
ASSERT_NE(nullptr, caller()->data_channel());
|
||||
ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
|
||||
EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||
EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||
|
||||
// SCTP transports should be present, since they are in use.
|
||||
EXPECT_NE(caller()->pc()->GetSctpTransport(), nullptr);
|
||||
EXPECT_NE(callee()->pc()->GetSctpTransport(), nullptr);
|
||||
|
||||
// Ensure data can be sent in both directions.
|
||||
std::string data = "hello world";
|
||||
caller()->data_channel()->Send(DataBuffer(data));
|
||||
EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
|
||||
kDefaultTimeout);
|
||||
callee()->data_channel()->Send(DataBuffer(data));
|
||||
EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
|
||||
kDefaultTimeout);
|
||||
}
|
||||
|
||||
#endif // HAVE_SCTP
|
||||
|
||||
// Tests that a callee configured for receive-only use of datagram transport
|
||||
// data channels accepts them on incoming calls.
|
||||
TEST_P(PeerConnectionIntegrationTest,
|
||||
DatagramTransportDataChannelReceiveOnlyOnCallee) {
|
||||
PeerConnectionInterface::RTCConfiguration offerer_config;
|
||||
offerer_config.rtcp_mux_policy =
|
||||
PeerConnectionInterface::kRtcpMuxPolicyRequire;
|
||||
offerer_config.bundle_policy =
|
||||
PeerConnectionInterface::kBundlePolicyMaxBundle;
|
||||
offerer_config.use_datagram_transport_for_data_channels = true;
|
||||
|
||||
PeerConnectionInterface::RTCConfiguration answerer_config;
|
||||
answerer_config.rtcp_mux_policy =
|
||||
PeerConnectionInterface::kRtcpMuxPolicyRequire;
|
||||
answerer_config.bundle_policy =
|
||||
PeerConnectionInterface::kBundlePolicyMaxBundle;
|
||||
answerer_config.use_datagram_transport_for_data_channels = true;
|
||||
answerer_config.use_datagram_transport_for_data_channels_receive_only = true;
|
||||
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappersWithConfigAndMediaTransportFactory(
|
||||
offerer_config, answerer_config,
|
||||
loopback_media_transports()->first_factory(),
|
||||
loopback_media_transports()->second_factory()));
|
||||
ConnectFakeSignaling();
|
||||
|
||||
caller()->CreateDataChannel();
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
// Ensure that the data channel transport is ready.
|
||||
loopback_media_transports()->SetState(webrtc::MediaTransportState::kWritable);
|
||||
loopback_media_transports()->FlushAsyncInvokes();
|
||||
|
||||
ASSERT_NE(nullptr, caller()->data_channel());
|
||||
ASSERT_TRUE_WAIT(callee()->data_channel() != nullptr, kDefaultTimeout);
|
||||
EXPECT_TRUE_WAIT(caller()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||
EXPECT_TRUE_WAIT(callee()->data_observer()->IsOpen(), kDefaultTimeout);
|
||||
|
||||
// SCTP transports should not be present, since datagram transport is used.
|
||||
EXPECT_EQ(caller()->pc()->GetSctpTransport(), nullptr);
|
||||
EXPECT_EQ(callee()->pc()->GetSctpTransport(), nullptr);
|
||||
|
||||
// Ensure data can be sent in both directions.
|
||||
std::string data = "hello world";
|
||||
caller()->data_channel()->Send(DataBuffer(data));
|
||||
EXPECT_EQ_WAIT(data, callee()->data_observer()->last_message(),
|
||||
kDefaultTimeout);
|
||||
callee()->data_channel()->Send(DataBuffer(data));
|
||||
EXPECT_EQ_WAIT(data, caller()->data_observer()->last_message(),
|
||||
kDefaultTimeout);
|
||||
}
|
||||
|
||||
// This test sets up a call between two parties with a datagram transport data
|
||||
// channel.
|
||||
TEST_P(PeerConnectionIntegrationTest, DatagramTransportDataChannelEndToEnd) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user