Promotoing webrtc::CryptoOptions to RTCConfiguration.

With the expanding use cases for webrtc::CryptoOptions it makes more sense for
it to be be available per peer connection instead of only as a factory option.

To support backwards compatability for now this code will support the factory
method of setting crypto options by default. However it will completely
overwrite these settings if an RTCConfiguration.crypto_options is provided.

Got LGTM offline from Sami, adding him to TBR if he has any further comments.

TBR=sakal@webrtc.org

Bug: webrtc:9891
Change-Id: I86914cab69284ad82afd7285fd84ec5f4f2c4986
Reviewed-on: https://webrtc-review.googlesource.com/c/107029
Commit-Queue: Benjamin Wright <benwright@webrtc.org>
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25375}
diff --git a/BUILD.gn b/BUILD.gn
index 1fcc310..d4e89fd 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -619,6 +619,7 @@
         "sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java",
         "sdk/android/tests/src/org/webrtc/HardwareVideoEncoderTest.java",
         "sdk/android/tests/src/org/webrtc/ScalingSettingsTest.java",
+        "sdk/android/tests/src/org/webrtc/CryptoOptionsTest.java",
       ]
 
       deps = [
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index 021be7d..6504f53 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -406,6 +406,7 @@
     // Use new combined audio/video bandwidth estimation?
     absl::optional<bool> combined_audio_video_bwe;
 
+    // TODO(bugs.webrtc.org/9891) - Move to crypto_options
     // Can be used to disable DTLS-SRTP. This should never be done, but can be
     // useful for testing purposes, for example in setting up a loopback call
     // with a single PeerConnection.
@@ -568,6 +569,7 @@
     // For all other users, specify kUnifiedPlan.
     SdpSemantics sdp_semantics = SdpSemantics::kPlanB;
 
+    // TODO(bugs.webrtc.org/9891) - Move to crypto_options or remove.
     // Actively reset the SRTP parameters whenever the DTLS transports
     // underneath are reset for every offer/answer negotiation.
     // This is only intended to be a workaround for crbug.com/835958
@@ -581,6 +583,11 @@
     // provided.
     bool use_media_transport = false;
 
+    // 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).
+    absl::optional<CryptoOptions> crypto_options;
+
     //
     // Don't forget to update operator== if adding something.
     //
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 9dc5e66..0876644 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -706,6 +706,7 @@
     absl::optional<rtc::AdapterType> network_preference;
     bool active_reset_srtp_params;
     bool use_media_transport;
+    absl::optional<CryptoOptions> crypto_options;
   };
   static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
                 "Did you add something to RTCConfiguration and forget to "
@@ -754,7 +755,8 @@
          sdp_semantics == o.sdp_semantics &&
          network_preference == o.network_preference &&
          active_reset_srtp_params == o.active_reset_srtp_params &&
-         use_media_transport == o.use_media_transport;
+         use_media_transport == o.use_media_transport &&
+         crypto_options == o.crypto_options;
 }
 
 bool PeerConnectionInterface::RTCConfiguration::operator!=(
@@ -932,7 +934,11 @@
   config.disable_encryption = options.disable_encryption;
   config.bundle_policy = configuration.bundle_policy;
   config.rtcp_mux_policy = configuration.rtcp_mux_policy;
-  config.crypto_options = options.crypto_options;
+  // TODO(bugs.webrtc.org/9891) - Remove options.crypto_options then remove this
+  // stub.
+  config.crypto_options = configuration.crypto_options.has_value()
+                              ? *configuration.crypto_options
+                              : options.crypto_options;
   config.transport_observer = this;
   config.event_log = event_log_.get();
 #if defined(ENABLE_EXTERNAL_AUTH)
@@ -1043,7 +1049,7 @@
   }
 
   webrtc_session_desc_factory_->set_enable_encrypted_rtp_header_extensions(
-      options.crypto_options.srtp.enable_encrypted_rtp_header_extensions);
+      GetCryptoOptions().srtp.enable_encrypted_rtp_header_extensions);
 
   // Add default audio/video transceivers for Plan B SDP.
   if (!IsUnifiedPlan()) {
@@ -2913,6 +2919,13 @@
     return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
   }
 
+  if (local_description() &&
+      configuration.crypto_options != configuration_.crypto_options) {
+    RTC_LOG(LS_ERROR) << "Can't change crypto_options after calling "
+                         "SetLocalDescription.";
+    return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
+  }
+
   // The simplest (and most future-compatible) way to tell if the config was
   // modified in an invalid way is to copy each property we do support
   // modifying, then use operator==. There are far more properties we don't
@@ -3715,7 +3728,7 @@
   }
 
   session_options->rtcp_cname = rtcp_cname_;
-  session_options->crypto_options = factory_->options().crypto_options;
+  session_options->crypto_options = GetCryptoOptions();
   session_options->is_unified_plan = IsUnifiedPlan();
   session_options->pooled_ice_credentials =
       network_thread()->Invoke<std::vector<cricket::IceParameters>>(
@@ -3980,7 +3993,7 @@
   }
 
   session_options->rtcp_cname = rtcp_cname_;
-  session_options->crypto_options = factory_->options().crypto_options;
+  session_options->crypto_options = GetCryptoOptions();
   session_options->is_unified_plan = IsUnifiedPlan();
   session_options->pooled_ice_credentials =
       network_thread()->Invoke<std::vector<cricket::IceParameters>>(
@@ -5588,8 +5601,8 @@
 
   cricket::VoiceChannel* voice_channel = channel_manager()->CreateVoiceChannel(
       call_.get(), configuration_.media_config, rtp_transport, media_transport,
-      signaling_thread(), mid, SrtpRequired(),
-      factory_->options().crypto_options, audio_options_);
+      signaling_thread(), mid, SrtpRequired(), GetCryptoOptions(),
+      audio_options_);
   if (!voice_channel) {
     return nullptr;
   }
@@ -5610,8 +5623,8 @@
   // TODO(sukhanov): Propagate media_transport to video channel.
   cricket::VideoChannel* video_channel = channel_manager()->CreateVideoChannel(
       call_.get(), configuration_.media_config, rtp_transport,
-      signaling_thread(), mid, SrtpRequired(),
-      factory_->options().crypto_options, video_options_);
+      signaling_thread(), mid, SrtpRequired(), GetCryptoOptions(),
+      video_options_);
   if (!video_channel) {
     return nullptr;
   }
@@ -5645,7 +5658,7 @@
     RtpTransportInternal* rtp_transport = GetRtpTransport(mid);
     rtp_data_channel_ = channel_manager()->CreateRtpDataChannel(
         configuration_.media_config, rtp_transport, signaling_thread(), mid,
-        SrtpRequired(), factory_->options().crypto_options);
+        SrtpRequired(), GetCryptoOptions());
     if (!rtp_data_channel_) {
       return false;
     }
@@ -6343,6 +6356,14 @@
   return observer_;
 }
 
+CryptoOptions PeerConnection::GetCryptoOptions() {
+  // TODO(bugs.webrtc.org/9891) - Remove PeerConnectionFactory::CryptoOptions
+  // after it has been removed.
+  return configuration_.crypto_options.has_value()
+             ? *configuration_.crypto_options
+             : factory_->options().crypto_options;
+}
+
 void PeerConnection::ClearStatsCache() {
   if (stats_collector_) {
     stats_collector_->ClearCachedStatsReport();
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index 604a5d3..e725798 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -922,6 +922,11 @@
   // Returns the observer. Will crash on CHECK if the observer is removed.
   PeerConnectionObserver* Observer() const;
 
+  // Returns the CryptoOptions for this PeerConnection. This will always
+  // return the RTCConfiguration.crypto_options if set and will only default
+  // back to the PeerConnectionFactory settings if nothing was set.
+  CryptoOptions GetCryptoOptions();
+
   // Returns rtp transport, result can not be nullptr.
   RtpTransportInternal* GetRtpTransport(const std::string& mid) {
     auto rtp_transport = transport_controller_->GetRtpTransport(mid);
diff --git a/pc/peerconnection_crypto_unittest.cc b/pc/peerconnection_crypto_unittest.cc
index 1a53d86..d61c41c 100644
--- a/pc/peerconnection_crypto_unittest.cc
+++ b/pc/peerconnection_crypto_unittest.cc
@@ -278,6 +278,28 @@
                              answer->description()));
 }
 
+// CryptoOptions has been promoted to RTCConfiguration. As such if it is ever
+// set in the configuration it should overrite the settings set in the factory.
+TEST_P(PeerConnectionCryptoTest, RTCConfigurationCryptoOptionOverridesFactory) {
+  PeerConnectionFactoryInterface::Options options;
+  options.crypto_options.srtp.enable_gcm_crypto_suites = true;
+  pc_factory_->SetOptions(options);
+
+  RTCConfiguration config;
+  config.enable_dtls_srtp.emplace(false);
+  CryptoOptions crypto_options;
+  crypto_options.srtp.enable_gcm_crypto_suites = false;
+  config.crypto_options = crypto_options;
+  auto caller = CreatePeerConnectionWithAudioVideo(config);
+
+  auto offer = caller->CreateOffer();
+  ASSERT_TRUE(offer);
+
+  ASSERT_FALSE(offer->description()->contents().empty());
+  // This should exist if GCM is enabled see CorrectCryptoInOfferWithSdesAndGcm
+  EXPECT_FALSE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
+}
+
 // When DTLS is disabled and GCM cipher suites are enabled, the SDP offer/answer
 // should have the correct ciphers in the SDES crypto options.
 // With GCM cipher suites enabled, there will be 3 cryptos in the offer and 1
@@ -297,6 +319,7 @@
   ASSERT_FALSE(offer->description()->contents().empty());
   EXPECT_TRUE(SdpContentsAll(HaveSdesGcmCryptos(3), offer->description()));
 }
+
 TEST_P(PeerConnectionCryptoTest, CorrectCryptoInAnswerWithSdesAndGcm) {
   PeerConnectionFactoryInterface::Options options;
   options.crypto_options.srtp.enable_gcm_crypto_suites = true;
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 03bdf3b..a8a1b03 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -797,6 +797,8 @@
         "objc/api/peerconnection/RTCConfiguration+Private.h",
         "objc/api/peerconnection/RTCConfiguration.h",
         "objc/api/peerconnection/RTCConfiguration.mm",
+        "objc/api/peerconnection/RTCCryptoOptions.h",
+        "objc/api/peerconnection/RTCCryptoOptions.mm",
         "objc/api/peerconnection/RTCDataChannel+Private.h",
         "objc/api/peerconnection/RTCDataChannel.h",
         "objc/api/peerconnection/RTCDataChannel.mm",
@@ -1274,6 +1276,7 @@
           "objc/api/peerconnection/RTCSessionDescription.h",
           "objc/api/peerconnection/RTCTracing.h",
           "objc/api/peerconnection/RTCCertificate.h",
+          "objc/api/peerconnection/RTCCryptoOptions.h",
           "objc/api/peerconnection/RTCVideoSource.h",
           "objc/api/peerconnection/RTCVideoTrack.h",
           "objc/api/video_codec/RTCVideoCodecConstants.h",
@@ -1362,6 +1365,7 @@
           "objc/api/peerconnection/RTCAudioTrack.h",
           "objc/api/peerconnection/RTCCertificate.h",
           "objc/api/peerconnection/RTCConfiguration.h",
+          "objc/api/peerconnection/RTCCryptoOptions.h",
           "objc/api/peerconnection/RTCDataChannel.h",
           "objc/api/peerconnection/RTCDataChannelConfiguration.h",
           "objc/api/peerconnection/RTCDtmfSender.h",
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 68cd77a..8a3f8cc 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -276,6 +276,7 @@
       "api/org/webrtc/AudioSource.java",
       "api/org/webrtc/AudioTrack.java",
       "api/org/webrtc/CallSessionFileRotatingLogSink.java",
+      "api/org/webrtc/CryptoOptions.java",
       "api/org/webrtc/DataChannel.java",
       "api/org/webrtc/DtmfSender.java",
       "api/org/webrtc/FecControllerFactoryFactoryInterface.java",
@@ -609,6 +610,8 @@
       "src/jni/pc/androidnetworkmonitor.h",
       "src/jni/pc/audiotrack.cc",
       "src/jni/pc/callsessionfilerotatinglogsink.cc",
+      "src/jni/pc/cryptooptions.cc",
+      "src/jni/pc/cryptooptions.h",
       "src/jni/pc/datachannel.cc",
       "src/jni/pc/datachannel.h",
       "src/jni/pc/dtmfsender.cc",
@@ -674,6 +677,7 @@
       "../../rtc_base:stringutils",
       "../../system_wrappers:field_trial",
       "//third_party/abseil-cpp/absl/memory",
+      "//third_party/abseil-cpp/absl/types:optional",
     ]
   }
 
@@ -1173,6 +1177,7 @@
     sources = [
       "api/org/webrtc/AudioTrack.java",
       "api/org/webrtc/CallSessionFileRotatingLogSink.java",
+      "api/org/webrtc/CryptoOptions.java",
       "api/org/webrtc/DataChannel.java",
       "api/org/webrtc/DtmfSender.java",
       "api/org/webrtc/IceCandidate.java",
diff --git a/sdk/android/api/org/webrtc/CryptoOptions.java b/sdk/android/api/org/webrtc/CryptoOptions.java
new file mode 100644
index 0000000..1ccc6df
--- /dev/null
+++ b/sdk/android/api/org/webrtc/CryptoOptions.java
@@ -0,0 +1,144 @@
+/*
+ *  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.
+ */
+package org.webrtc;
+
+/**
+ * CryptoOptions defines advanced cryptographic settings for native WebRTC.
+ * These settings must be passed into RTCConfiguration. WebRTC is secur by
+ * default and you should not need to set any of these options unless you are
+ * specifically looking for an additional crypto feature such as AES_GCM
+ * support. This class is the Java binding of native api/crypto/cryptooptions.h
+ */
+public final class CryptoOptions {
+  /**
+   * SRTP Related Peer Connection Options.
+   */
+  public final class Srtp {
+    /**
+     * Enable GCM crypto suites from RFC 7714 for SRTP. GCM will only be used
+     * if both sides enable it
+     */
+    private final boolean enableGcmCryptoSuites;
+    /**
+     * If set to true, the (potentially insecure) crypto cipher
+     * SRTP_AES128_CM_SHA1_32 will be included in the list of supported ciphers
+     * during negotiation. It will only be used if both peers support it and no
+     * other ciphers get preferred.
+     */
+    private final boolean enableAes128Sha1_32CryptoCipher;
+    /**
+     * If set to true, encrypted RTP header extensions as defined in RFC 6904
+     * will be negotiated. They will only be used if both peers support them.
+     */
+    private final boolean enableEncryptedRtpHeaderExtensions;
+
+    private Srtp(boolean enableGcmCryptoSuites, boolean enableAes128Sha1_32CryptoCipher,
+        boolean enableEncryptedRtpHeaderExtensions) {
+      this.enableGcmCryptoSuites = enableGcmCryptoSuites;
+      this.enableAes128Sha1_32CryptoCipher = enableAes128Sha1_32CryptoCipher;
+      this.enableEncryptedRtpHeaderExtensions = enableEncryptedRtpHeaderExtensions;
+    }
+
+    @CalledByNative("Srtp")
+    public boolean getEnableGcmCryptoSuites() {
+      return enableGcmCryptoSuites;
+    }
+
+    @CalledByNative("Srtp")
+    public boolean getEnableAes128Sha1_32CryptoCipher() {
+      return enableAes128Sha1_32CryptoCipher;
+    }
+
+    @CalledByNative("Srtp")
+    public boolean getEnableEncryptedRtpHeaderExtensions() {
+      return enableEncryptedRtpHeaderExtensions;
+    }
+  }
+
+  /**
+   * Options to be used when the FrameEncryptor / FrameDecryptor APIs are used.
+   */
+  public final class SFrame {
+    /**
+     * If set all RtpSenders must have an FrameEncryptor attached to them before
+     * they are allowed to send packets. All RtpReceivers must have a
+     * FrameDecryptor attached to them before they are able to receive packets.
+     */
+    private final boolean requireFrameEncryption;
+
+    private SFrame(boolean requireFrameEncryption) {
+      this.requireFrameEncryption = requireFrameEncryption;
+    }
+
+    @CalledByNative("SFrame")
+    public boolean getRequireFrameEncryption() {
+      return requireFrameEncryption;
+    }
+  }
+
+  private final Srtp srtp;
+  private final SFrame sframe;
+
+  private CryptoOptions(boolean enableGcmCryptoSuites, boolean enableAes128Sha1_32CryptoCipher,
+      boolean enableEncryptedRtpHeaderExtensions, boolean requireFrameEncryption) {
+    this.srtp = new Srtp(
+        enableGcmCryptoSuites, enableAes128Sha1_32CryptoCipher, enableEncryptedRtpHeaderExtensions);
+    this.sframe = new SFrame(requireFrameEncryption);
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @CalledByNative
+  public Srtp getSrtp() {
+    return srtp;
+  }
+
+  @CalledByNative
+  public SFrame getSFrame() {
+    return sframe;
+  }
+
+  public static class Builder {
+    private boolean enableGcmCryptoSuites = false;
+    private boolean enableAes128Sha1_32CryptoCipher = false;
+    private boolean enableEncryptedRtpHeaderExtensions = false;
+    private boolean requireFrameEncryption = false;
+
+    private Builder() {}
+
+    public Builder setEnableGcmCryptoSuites(boolean enableGcmCryptoSuites) {
+      this.enableGcmCryptoSuites = enableGcmCryptoSuites;
+      return this;
+    }
+
+    public Builder setEnableAes128Sha1_32CryptoCipher(boolean enableAes128Sha1_32CryptoCipher) {
+      this.enableAes128Sha1_32CryptoCipher = enableAes128Sha1_32CryptoCipher;
+      return this;
+    }
+
+    public Builder setEnableEncryptedRtpHeaderExtensions(
+        boolean enableEncryptedRtpHeaderExtensions) {
+      this.enableEncryptedRtpHeaderExtensions = enableEncryptedRtpHeaderExtensions;
+      return this;
+    }
+
+    public Builder setRequireFrameEncryption(boolean requireFrameEncryption) {
+      this.requireFrameEncryption = requireFrameEncryption;
+      return this;
+    }
+
+    public CryptoOptions createCryptoOptions() {
+      return new CryptoOptions(enableGcmCryptoSuites, enableAes128Sha1_32CryptoCipher,
+          enableEncryptedRtpHeaderExtensions, requireFrameEncryption);
+    }
+  }
+}
diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java
index d50819c..1cb5717 100644
--- a/sdk/android/api/org/webrtc/PeerConnection.java
+++ b/sdk/android/api/org/webrtc/PeerConnection.java
@@ -468,6 +468,13 @@
      */
     public boolean useMediaTransport;
 
+    /**
+     * Defines advanced optional cryptographic settings related to SRTP and
+     * frame encryption for native WebRTC. Setting this will overwrite any
+     * options set through the PeerConnectionFactory (which is deprecated).
+     */
+    @Nullable public CryptoOptions cryptoOptions;
+
     // TODO(deadbeef): Instead of duplicating the defaults here, we should do
     // something to pick up the defaults from C++. The Objective-C equivalent
     // of RTCConfiguration does that.
@@ -508,6 +515,7 @@
       sdpSemantics = SdpSemantics.PLAN_B;
       activeResetSrtpParams = false;
       useMediaTransport = false;
+      cryptoOptions = null;
     }
 
     @CalledByNative("RTCConfiguration")
@@ -711,6 +719,12 @@
     boolean getUseMediaTransport() {
       return useMediaTransport;
     }
+
+    @Nullable
+    @CalledByNative("RTCConfiguration")
+    CryptoOptions getCryptoOptions() {
+      return cryptoOptions;
+    }
   };
 
   private final List<MediaStream> localStreams = new ArrayList<>();
diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
index fdc29bb..5e2289c 100644
--- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java
+++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
@@ -123,6 +123,9 @@
     public boolean disableEncryption;
     public boolean disableNetworkMonitor;
 
+    // TODO(webrtc:9891) - The below crypto options are deprecated. Please use
+    // RTCConfiguration to set these options instead. They will be removed in
+    // a future release.
     /**
      * If set to true, the (potentially insecure) crypto cipher SRTP_AES128_CM_SHA1_32
      * will be included in the list of supported ciphers during negotiation. It will only
@@ -158,16 +161,19 @@
       return disableNetworkMonitor;
     }
 
+    @Deprecated
     @CalledByNative("Options")
     boolean getEnableAes128Sha1_32CryptoCipher() {
       return enableAes128Sha1_32CryptoCipher;
     }
 
+    @Deprecated
     @CalledByNative("Options")
     boolean getEnableGcmCryptoSuites() {
       return enableGcmCryptoSuites;
     }
 
+    @Deprecated
     @CalledByNative("Options")
     boolean getRequireFrameEncryption() {
       return requireFrameEncryption;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
index 894e2bd..cd24037 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java
@@ -683,6 +683,27 @@
   }
 
   @Test
+  @SmallTest
+  public void testCreationWithCryptoOptions() throws Exception {
+    PeerConnectionFactory factory = PeerConnectionFactory.builder().createPeerConnectionFactory();
+    PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Arrays.asList());
+
+    assertNull(config.cryptoOptions);
+
+    CryptoOptions cryptoOptions = CryptoOptions.builder()
+                                      .setEnableGcmCryptoSuites(true)
+                                      .setEnableAes128Sha1_32CryptoCipher(true)
+                                      .setEnableEncryptedRtpHeaderExtensions(true)
+                                      .setRequireFrameEncryption(true)
+                                      .createCryptoOptions();
+    config.cryptoOptions = cryptoOptions;
+
+    ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer");
+    PeerConnection offeringPC = factory.createPeerConnection(config, offeringExpectations);
+    assertNotNull(offeringPC);
+  }
+
+  @Test
   @MediumTest
   public void testCompleteSession() throws Exception {
     Metrics.enable();
diff --git a/sdk/android/src/jni/pc/cryptooptions.cc b/sdk/android/src/jni/pc/cryptooptions.cc
new file mode 100644
index 0000000..0f38b13
--- /dev/null
+++ b/sdk/android/src/jni/pc/cryptooptions.cc
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ */
+
+#include "sdk/android/src/jni/pc/cryptooptions.h"
+
+#include "sdk/android/generated_peerconnection_jni/jni/CryptoOptions_jni.h"
+
+namespace webrtc {
+namespace jni {
+
+absl::optional<CryptoOptions> JavaToNativeOptionalCryptoOptions(
+    JNIEnv* jni,
+    const JavaRef<jobject>& j_crypto_options) {
+  if (j_crypto_options.is_null()) {
+    return absl::nullopt;
+  }
+
+  ScopedJavaLocalRef<jobject> j_srtp =
+      Java_CryptoOptions_getSrtp(jni, j_crypto_options);
+  ScopedJavaLocalRef<jobject> j_sframe =
+      Java_CryptoOptions_getSFrame(jni, j_crypto_options);
+
+  CryptoOptions native_crypto_options;
+  native_crypto_options.srtp.enable_gcm_crypto_suites =
+      Java_Srtp_getEnableGcmCryptoSuites(jni, j_srtp);
+  native_crypto_options.srtp.enable_aes128_sha1_32_crypto_cipher =
+      Java_Srtp_getEnableAes128Sha1_32CryptoCipher(jni, j_srtp);
+  native_crypto_options.srtp.enable_encrypted_rtp_header_extensions =
+      Java_Srtp_getEnableEncryptedRtpHeaderExtensions(jni, j_srtp);
+  native_crypto_options.sframe.require_frame_encryption =
+      Java_SFrame_getRequireFrameEncryption(jni, j_sframe);
+  return absl::optional<CryptoOptions>(native_crypto_options);
+}
+
+}  // namespace jni
+}  // namespace webrtc
diff --git a/sdk/android/src/jni/pc/cryptooptions.h b/sdk/android/src/jni/pc/cryptooptions.h
new file mode 100644
index 0000000..9890264
--- /dev/null
+++ b/sdk/android/src/jni/pc/cryptooptions.h
@@ -0,0 +1,30 @@
+/*
+ *  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 SDK_ANDROID_SRC_JNI_PC_CRYPTOOPTIONS_H_
+#define SDK_ANDROID_SRC_JNI_PC_CRYPTOOPTIONS_H_
+
+#include <jni.h>
+
+#include "absl/types/optional.h"
+#include "api/crypto/cryptooptions.h"
+#include "sdk/android/native_api/jni/scoped_java_ref.h"
+
+namespace webrtc {
+namespace jni {
+
+absl::optional<CryptoOptions> JavaToNativeOptionalCryptoOptions(
+    JNIEnv* jni,
+    const JavaRef<jobject>& j_crypto_options);
+
+}  // namespace jni
+}  // namespace webrtc
+
+#endif  // SDK_ANDROID_SRC_JNI_PC_CRYPTOOPTIONS_H_
diff --git a/sdk/android/src/jni/pc/peerconnection.cc b/sdk/android/src/jni/pc/peerconnection.cc
index 8a29199..0d51847 100644
--- a/sdk/android/src/jni/pc/peerconnection.cc
+++ b/sdk/android/src/jni/pc/peerconnection.cc
@@ -43,6 +43,7 @@
 #include "sdk/android/generated_peerconnection_jni/jni/PeerConnection_jni.h"
 #include "sdk/android/native_api/jni/java_types.h"
 #include "sdk/android/src/jni/jni_helpers.h"
+#include "sdk/android/src/jni/pc/cryptooptions.h"
 #include "sdk/android/src/jni/pc/datachannel.h"
 #include "sdk/android/src/jni/pc/icecandidate.h"
 #include "sdk/android/src/jni/pc/mediaconstraints.h"
@@ -146,6 +147,8 @@
       Java_RTCConfiguration_getNetworkPreference(jni, j_rtc_config);
   ScopedJavaLocalRef<jobject> j_sdp_semantics =
       Java_RTCConfiguration_getSdpSemantics(jni, j_rtc_config);
+  ScopedJavaLocalRef<jobject> j_crypto_options =
+      Java_RTCConfiguration_getCryptoOptions(jni, j_rtc_config);
 
   rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type);
   rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy);
@@ -246,6 +249,8 @@
       Java_RTCConfiguration_getActiveResetSrtpParams(jni, j_rtc_config);
   rtc_config->use_media_transport =
       Java_RTCConfiguration_getUseMediaTransport(jni, j_rtc_config);
+  rtc_config->crypto_options =
+      JavaToNativeOptionalCryptoOptions(jni, j_crypto_options);
 }
 
 rtc::KeyType GetRtcConfigKeyType(JNIEnv* env,
diff --git a/sdk/android/tests/src/org/webrtc/CryptoOptionsTest.java b/sdk/android/tests/src/org/webrtc/CryptoOptionsTest.java
new file mode 100644
index 0000000..f03811e
--- /dev/null
+++ b/sdk/android/tests/src/org/webrtc/CryptoOptionsTest.java
@@ -0,0 +1,74 @@
+/*
+ *  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.
+ */
+
+package org.webrtc;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.webrtc.CryptoOptions;
+
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class CryptoOptionsTest {
+  // Validates the builder builds by default all false options.
+  @Test
+  public void testBuilderDefaultsAreFalse() {
+    CryptoOptions cryptoOptions = CryptoOptions.builder().createCryptoOptions();
+    assertThat(cryptoOptions.getSrtp().getEnableGcmCryptoSuites()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableAes128Sha1_32CryptoCipher()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableEncryptedRtpHeaderExtensions()).isFalse();
+    assertThat(cryptoOptions.getSFrame().getRequireFrameEncryption()).isFalse();
+  }
+
+  // Validates the builder sets the correct parameters.
+  @Test
+  public void testBuilderCorrectlyInitializingGcmCrypto() {
+    CryptoOptions cryptoOptions =
+        CryptoOptions.builder().setEnableGcmCryptoSuites(true).createCryptoOptions();
+    assertThat(cryptoOptions.getSrtp().getEnableGcmCryptoSuites()).isTrue();
+    assertThat(cryptoOptions.getSrtp().getEnableAes128Sha1_32CryptoCipher()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableEncryptedRtpHeaderExtensions()).isFalse();
+    assertThat(cryptoOptions.getSFrame().getRequireFrameEncryption()).isFalse();
+  }
+
+  @Test
+  public void testBuilderCorrectlyInitializingAes128Sha1_32CryptoCipher() {
+    CryptoOptions cryptoOptions =
+        CryptoOptions.builder().setEnableAes128Sha1_32CryptoCipher(true).createCryptoOptions();
+    assertThat(cryptoOptions.getSrtp().getEnableGcmCryptoSuites()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableAes128Sha1_32CryptoCipher()).isTrue();
+    assertThat(cryptoOptions.getSrtp().getEnableEncryptedRtpHeaderExtensions()).isFalse();
+    assertThat(cryptoOptions.getSFrame().getRequireFrameEncryption()).isFalse();
+  }
+
+  @Test
+  public void testBuilderCorrectlyInitializingEncryptedRtpHeaderExtensions() {
+    CryptoOptions cryptoOptions =
+        CryptoOptions.builder().setEnableEncryptedRtpHeaderExtensions(true).createCryptoOptions();
+    assertThat(cryptoOptions.getSrtp().getEnableGcmCryptoSuites()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableAes128Sha1_32CryptoCipher()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableEncryptedRtpHeaderExtensions()).isTrue();
+    assertThat(cryptoOptions.getSFrame().getRequireFrameEncryption()).isFalse();
+  }
+
+  @Test
+  public void testBuilderCorrectlyInitializingRequireFrameEncryption() {
+    CryptoOptions cryptoOptions =
+        CryptoOptions.builder().setRequireFrameEncryption(true).createCryptoOptions();
+    assertThat(cryptoOptions.getSrtp().getEnableGcmCryptoSuites()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableAes128Sha1_32CryptoCipher()).isFalse();
+    assertThat(cryptoOptions.getSrtp().getEnableEncryptedRtpHeaderExtensions()).isFalse();
+    assertThat(cryptoOptions.getSFrame().getRequireFrameEncryption()).isTrue();
+  }
+}
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.h b/sdk/objc/api/peerconnection/RTCConfiguration.h
index c7998a5..9f41fd2 100644
--- a/sdk/objc/api/peerconnection/RTCConfiguration.h
+++ b/sdk/objc/api/peerconnection/RTCConfiguration.h
@@ -11,6 +11,7 @@
 #import <Foundation/Foundation.h>
 
 #import "RTCCertificate.h"
+#import "RTCCryptoOptions.h"
 #import "RTCMacros.h"
 
 @class RTCIceServer;
@@ -174,6 +175,13 @@
  */
 @property(nonatomic, assign) BOOL useMediaTransport;
 
+/**
+ * Defines advanced optional cryptographic settings related to SRTP and
+ * frame encryption for native WebRTC. Setting this will overwrite any
+ * options set through the PeerConnectionFactory (which is deprecated).
+ */
+@property(nonatomic, nullable) RTCCryptoOptions *cryptoOptions;
+
 - (instancetype)init;
 
 @end
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.mm b/sdk/objc/api/peerconnection/RTCConfiguration.mm
index bdf4fb6..35cdc46 100644
--- a/sdk/objc/api/peerconnection/RTCConfiguration.mm
+++ b/sdk/objc/api/peerconnection/RTCConfiguration.mm
@@ -49,6 +49,7 @@
 @synthesize turnCustomizer = _turnCustomizer;
 @synthesize activeResetSrtpParams = _activeResetSrtpParams;
 @synthesize useMediaTransport = _useMediaTransport;
+@synthesize cryptoOptions = _cryptoOptions;
 
 - (instancetype)init {
   // Copy defaults.
@@ -111,6 +112,17 @@
     _sdpSemantics = [[self class] sdpSemanticsForNativeSdpSemantics:config.sdp_semantics];
     _turnCustomizer = config.turn_customizer;
     _activeResetSrtpParams = config.active_reset_srtp_params;
+    if (config.crypto_options) {
+      _cryptoOptions = [[RTCCryptoOptions alloc]
+               initWithSrtpEnableGcmCryptoSuites:config.crypto_options->srtp
+                                                     .enable_gcm_crypto_suites
+             srtpEnableAes128Sha1_32CryptoCipher:config.crypto_options->srtp
+                                                     .enable_aes128_sha1_32_crypto_cipher
+          srtpEnableEncryptedRtpHeaderExtensions:config.crypto_options->srtp
+                                                     .enable_encrypted_rtp_header_extensions
+                    sframeRequireFrameEncryption:config.crypto_options->sframe
+                                                     .require_frame_encryption];
+    }
   }
   return self;
 }
@@ -224,6 +236,19 @@
     nativeConfig->turn_customizer = _turnCustomizer;
   }
   nativeConfig->active_reset_srtp_params = _activeResetSrtpParams ? true : false;
+  if (_cryptoOptions) {
+    webrtc::CryptoOptions nativeCryptoOptions;
+    nativeCryptoOptions.srtp.enable_gcm_crypto_suites =
+        _cryptoOptions.srtpEnableGcmCryptoSuites ? true : false;
+    nativeCryptoOptions.srtp.enable_aes128_sha1_32_crypto_cipher =
+        _cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher ? true : false;
+    nativeCryptoOptions.srtp.enable_encrypted_rtp_header_extensions =
+        _cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions ? true : false;
+    nativeCryptoOptions.sframe.require_frame_encryption =
+        _cryptoOptions.sframeRequireFrameEncryption ? true : false;
+    nativeConfig->crypto_options = absl::optional<webrtc::CryptoOptions>(nativeCryptoOptions);
+  }
+
   return nativeConfig.release();
 }
 
diff --git a/sdk/objc/api/peerconnection/RTCCryptoOptions.h b/sdk/objc/api/peerconnection/RTCCryptoOptions.h
new file mode 100644
index 0000000..b465bb5
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCCryptoOptions.h
@@ -0,0 +1,63 @@
+/*
+ *  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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Objective-C bindings for webrtc::CryptoOptions. This API had to be flattened
+ * as Objective-C doesn't support nested structures.
+ */
+RTC_OBJC_EXPORT
+@interface RTCCryptoOptions : NSObject
+
+/**
+ * Enable GCM crypto suites from RFC 7714 for SRTP. GCM will only be used
+ * if both sides enable it
+ */
+@property(nonatomic, assign) BOOL srtpEnableGcmCryptoSuites;
+/**
+ * If set to true, the (potentially insecure) crypto cipher
+ * SRTP_AES128_CM_SHA1_32 will be included in the list of supported ciphers
+ * during negotiation. It will only be used if both peers support it and no
+ * other ciphers get preferred.
+ */
+@property(nonatomic, assign) BOOL srtpEnableAes128Sha1_32CryptoCipher;
+/**
+ * If set to true, encrypted RTP header extensions as defined in RFC 6904
+ * will be negotiated. They will only be used if both peers support them.
+ */
+@property(nonatomic, assign) BOOL srtpEnableEncryptedRtpHeaderExtensions;
+
+/**
+ * If set all RtpSenders must have an FrameEncryptor attached to them before
+ * they are allowed to send packets. All RtpReceivers must have a
+ * FrameDecryptor attached to them before they are able to receive packets.
+ */
+@property(nonatomic, assign) BOOL sframeRequireFrameEncryption;
+
+/**
+ * Initializes CryptoOptions with all possible options set explicitly. This
+ * is done when converting from a native RTCConfiguration.crypto_options.
+ */
+- (instancetype)initWithSrtpEnableGcmCryptoSuites:(BOOL)srtpEnableGcmCryptoSuites
+              srtpEnableAes128Sha1_32CryptoCipher:(BOOL)srtpEnableAes128Sha1_32CryptoCipher
+           srtpEnableEncryptedRtpHeaderExtensions:(BOOL)srtpEnableEncryptedRtpHeaderExtensions
+                     sframeRequireFrameEncryption:(BOOL)sframeRequireFrameEncryption
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCCryptoOptions.mm b/sdk/objc/api/peerconnection/RTCCryptoOptions.mm
new file mode 100644
index 0000000..a059f75
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCCryptoOptions.mm
@@ -0,0 +1,33 @@
+/*
+ *  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.
+ */
+
+#import "RTCCryptoOptions.h"
+
+@implementation RTCCryptoOptions
+
+@synthesize srtpEnableGcmCryptoSuites = _srtpEnableGcmCryptoSuites;
+@synthesize srtpEnableAes128Sha1_32CryptoCipher = _srtpEnableAes128Sha1_32CryptoCipher;
+@synthesize srtpEnableEncryptedRtpHeaderExtensions = _srtpEnableEncryptedRtpHeaderExtensions;
+@synthesize sframeRequireFrameEncryption = _sframeRequireFrameEncryption;
+
+- (instancetype)initWithSrtpEnableGcmCryptoSuites:(BOOL)srtpEnableGcmCryptoSuites
+              srtpEnableAes128Sha1_32CryptoCipher:(BOOL)srtpEnableAes128Sha1_32CryptoCipher
+           srtpEnableEncryptedRtpHeaderExtensions:(BOOL)srtpEnableEncryptedRtpHeaderExtensions
+                     sframeRequireFrameEncryption:(BOOL)sframeRequireFrameEncryption {
+  if (self = [super init]) {
+    _srtpEnableGcmCryptoSuites = srtpEnableGcmCryptoSuites;
+    _srtpEnableAes128Sha1_32CryptoCipher = srtpEnableAes128Sha1_32CryptoCipher;
+    _srtpEnableEncryptedRtpHeaderExtensions = srtpEnableEncryptedRtpHeaderExtensions;
+    _sframeRequireFrameEncryption = sframeRequireFrameEncryption;
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/unittests/RTCConfigurationTest.mm b/sdk/objc/unittests/RTCConfigurationTest.mm
index 1ef718a..67a303e 100644
--- a/sdk/objc/unittests/RTCConfigurationTest.mm
+++ b/sdk/objc/unittests/RTCConfigurationTest.mm
@@ -50,6 +50,10 @@
       RTCContinualGatheringPolicyGatherContinually;
   config.shouldPruneTurnPorts = YES;
   config.iceRegatherIntervalRange = range;
+  config.cryptoOptions = [[RTCCryptoOptions alloc] initWithSrtpEnableGcmCryptoSuites:YES
+                                                 srtpEnableAes128Sha1_32CryptoCipher:YES
+                                              srtpEnableEncryptedRtpHeaderExtensions:YES
+                                                        sframeRequireFrameEncryption:YES];
 
   std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration>
       nativeConfig([config createNativeConfiguration]);
@@ -78,6 +82,10 @@
   EXPECT_EQ(true, nativeConfig->prune_turn_ports);
   EXPECT_EQ(range.min, nativeConfig->ice_regather_interval_range->min());
   EXPECT_EQ(range.max, nativeConfig->ice_regather_interval_range->max());
+  EXPECT_EQ(true, nativeConfig->crypto_options->srtp.enable_gcm_crypto_suites);
+  EXPECT_EQ(true, nativeConfig->crypto_options->srtp.enable_aes128_sha1_32_crypto_cipher);
+  EXPECT_EQ(true, nativeConfig->crypto_options->srtp.enable_encrypted_rtp_header_extensions);
+  EXPECT_EQ(true, nativeConfig->crypto_options->sframe.require_frame_encryption);
 }
 
 - (void)testNativeConversionToConfiguration {
@@ -103,6 +111,10 @@
       RTCContinualGatheringPolicyGatherContinually;
   config.shouldPruneTurnPorts = YES;
   config.iceRegatherIntervalRange = range;
+  config.cryptoOptions = [[RTCCryptoOptions alloc] initWithSrtpEnableGcmCryptoSuites:YES
+                                                 srtpEnableAes128Sha1_32CryptoCipher:NO
+                                              srtpEnableEncryptedRtpHeaderExtensions:NO
+                                                        sframeRequireFrameEncryption:NO];
 
   webrtc::PeerConnectionInterface::RTCConfiguration *nativeConfig =
       [config createNativeConfiguration];
@@ -130,6 +142,19 @@
   EXPECT_EQ(config.shouldPruneTurnPorts, newConfig.shouldPruneTurnPorts);
   EXPECT_EQ(config.iceRegatherIntervalRange.min, newConfig.iceRegatherIntervalRange.min);
   EXPECT_EQ(config.iceRegatherIntervalRange.max, newConfig.iceRegatherIntervalRange.max);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableGcmCryptoSuites,
+            newConfig.cryptoOptions.srtpEnableGcmCryptoSuites);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher,
+            newConfig.cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions,
+            newConfig.cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions);
+  EXPECT_EQ(config.cryptoOptions.sframeRequireFrameEncryption,
+            newConfig.cryptoOptions.sframeRequireFrameEncryption);
+}
+
+- (void)testDefaultValues {
+  RTCConfiguration *config = [[RTCConfiguration alloc] init];
+  EXPECT_EQ(config.cryptoOptions, nil);
 }
 
 @end
@@ -139,5 +164,6 @@
     RTCConfigurationTest *test = [[RTCConfigurationTest alloc] init];
     [test testConversionToNativeConfiguration];
     [test testNativeConversionToConfiguration];
+    [test testDefaultValues];
   }
 }
diff --git a/sdk/objc/unittests/RTCPeerConnectionTest.mm b/sdk/objc/unittests/RTCPeerConnectionTest.mm
index 28fdee6..3532258 100644
--- a/sdk/objc/unittests/RTCPeerConnectionTest.mm
+++ b/sdk/objc/unittests/RTCPeerConnectionTest.mm
@@ -16,6 +16,7 @@
 
 #import "api/peerconnection/RTCConfiguration+Private.h"
 #import "api/peerconnection/RTCConfiguration.h"
+#import "api/peerconnection/RTCCryptoOptions.h"
 #import "api/peerconnection/RTCIceServer.h"
 #import "api/peerconnection/RTCMediaConstraints.h"
 #import "api/peerconnection/RTCPeerConnection.h"
@@ -50,6 +51,10 @@
       RTCContinualGatheringPolicyGatherContinually;
   config.shouldPruneTurnPorts = YES;
   config.activeResetSrtpParams = YES;
+  config.cryptoOptions = [[RTCCryptoOptions alloc] initWithSrtpEnableGcmCryptoSuites:YES
+                                                 srtpEnableAes128Sha1_32CryptoCipher:YES
+                                              srtpEnableEncryptedRtpHeaderExtensions:NO
+                                                        sframeRequireFrameEncryption:NO];
 
   RTCMediaConstraints *contraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{}
       optionalConstraints:nil];
@@ -89,6 +94,14 @@
   EXPECT_EQ(config.continualGatheringPolicy, newConfig.continualGatheringPolicy);
   EXPECT_EQ(config.shouldPruneTurnPorts, newConfig.shouldPruneTurnPorts);
   EXPECT_EQ(config.activeResetSrtpParams, newConfig.activeResetSrtpParams);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableGcmCryptoSuites,
+            newConfig.cryptoOptions.srtpEnableGcmCryptoSuites);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher,
+            newConfig.cryptoOptions.srtpEnableAes128Sha1_32CryptoCipher);
+  EXPECT_EQ(config.cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions,
+            newConfig.cryptoOptions.srtpEnableEncryptedRtpHeaderExtensions);
+  EXPECT_EQ(config.cryptoOptions.sframeRequireFrameEncryption,
+            newConfig.cryptoOptions.sframeRequireFrameEncryption);
 }
 
 @end