Obj-C SDK Cleanup

This CL separates the files under sdk/objc into logical directories, replacing
the previous file layout under Framework/.

A long term goal is to have some system set up to generate the files under
sdk/objc/api (the PeerConnection API wrappers) from the C++ code. In the shorter
term the goal is to abstract out shared concepts from these classes in order to
make them as uniform as possible.

The separation into base/, components/, and helpers/ are to differentiate between
the base layer's common protocols, various utilities and the actual platform
specific components.

The old directory layout that resembled a framework's internal layout is not
necessary, since it is generated by the framework target when building it.

Bug: webrtc:9627
Change-Id: Ib084fd83f050ae980649ca99e841f4fb0580bd8f
Reviewed-on: https://webrtc-review.googlesource.com/94142
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Anders Carlsson <andersc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24493}
diff --git a/sdk/objc/api/RTCVideoRendererAdapter+Private.h b/sdk/objc/api/RTCVideoRendererAdapter+Private.h
new file mode 100644
index 0000000..7cedba4
--- /dev/null
+++ b/sdk/objc/api/RTCVideoRendererAdapter+Private.h
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2015 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 "RTCVideoRendererAdapter.h"
+
+#import "base/RTCVideoRenderer.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCVideoRendererAdapter ()
+
+/**
+ * The Objective-C video renderer passed to this adapter during construction.
+ * Calls made to the webrtc::VideoRenderInterface will be adapted and passed to
+ * this video renderer.
+ */
+@property(nonatomic, readonly) id<RTCVideoRenderer> videoRenderer;
+
+/**
+ * The native VideoSinkInterface surface exposed by this adapter. Calls made
+ * to this interface will be adapted and passed to the RTCVideoRenderer supplied
+ * during construction. This pointer is unsafe and owned by this class.
+ */
+@property(nonatomic, readonly) rtc::VideoSinkInterface<webrtc::VideoFrame> *nativeVideoRenderer;
+
+/** Initialize an RTCVideoRendererAdapter with an RTCVideoRenderer. */
+- (instancetype)initWithNativeRenderer:(id<RTCVideoRenderer>)videoRenderer
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/RTCVideoRendererAdapter.h b/sdk/objc/api/RTCVideoRendererAdapter.h
new file mode 100644
index 0000000..b0b6f04
--- /dev/null
+++ b/sdk/objc/api/RTCVideoRendererAdapter.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2015 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>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/*
+ * Creates a rtc::VideoSinkInterface surface for an RTCVideoRenderer. The
+ * rtc::VideoSinkInterface is used by WebRTC rendering code - this
+ * adapter adapts calls made to that interface to the RTCVideoRenderer supplied
+ * during construction.
+ */
+@interface RTCVideoRendererAdapter : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/RTCVideoRendererAdapter.mm b/sdk/objc/api/RTCVideoRendererAdapter.mm
new file mode 100644
index 0000000..d30c4e7
--- /dev/null
+++ b/sdk/objc/api/RTCVideoRendererAdapter.mm
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2015 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 "RTCVideoRendererAdapter+Private.h"
+#import "api/video_frame_buffer/RTCI420Buffer+Private.h"
+#import "base/RTCVideoFrame.h"
+#import "base/RTCVideoFrameBuffer.h"
+
+#include <memory>
+
+#include "sdk/objc/native/api/video_frame.h"
+
+namespace webrtc {
+
+class VideoRendererAdapter
+    : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
+ public:
+  VideoRendererAdapter(RTCVideoRendererAdapter* adapter) {
+    adapter_ = adapter;
+    size_ = CGSizeZero;
+  }
+
+  void OnFrame(const webrtc::VideoFrame& nativeVideoFrame) override {
+    RTCVideoFrame* videoFrame = NativeToObjCVideoFrame(nativeVideoFrame);
+
+    CGSize current_size = (videoFrame.rotation % 180 == 0)
+                              ? CGSizeMake(videoFrame.width, videoFrame.height)
+                              : CGSizeMake(videoFrame.height, videoFrame.width);
+
+    if (!CGSizeEqualToSize(size_, current_size)) {
+      size_ = current_size;
+      [adapter_.videoRenderer setSize:size_];
+    }
+    [adapter_.videoRenderer renderFrame:videoFrame];
+  }
+
+ private:
+  __weak RTCVideoRendererAdapter *adapter_;
+  CGSize size_;
+};
+}
+
+@implementation RTCVideoRendererAdapter {
+  std::unique_ptr<webrtc::VideoRendererAdapter> _adapter;
+}
+
+@synthesize videoRenderer = _videoRenderer;
+
+- (instancetype)initWithNativeRenderer:(id<RTCVideoRenderer>)videoRenderer {
+  NSParameterAssert(videoRenderer);
+  if (self = [super init]) {
+    _videoRenderer = videoRenderer;
+    _adapter.reset(new webrtc::VideoRendererAdapter(self));
+  }
+  return self;
+}
+
+- (rtc::VideoSinkInterface<webrtc::VideoFrame> *)nativeVideoRenderer {
+  return _adapter.get();
+}
+
+@end
diff --git a/sdk/objc/api/logging/RTCCallbackLogger.h b/sdk/objc/api/logging/RTCCallbackLogger.h
new file mode 100644
index 0000000..669f2a3
--- /dev/null
+++ b/sdk/objc/api/logging/RTCCallbackLogger.h
@@ -0,0 +1,35 @@
+/*
+ *  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 "RTCLogging.h"
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// This class intercepts WebRTC logs and forwards them to a registered block.
+// This class is not threadsafe.
+RTC_EXPORT
+@interface RTCCallbackLogger : NSObject
+
+// The severity level to capture. The default is kRTCLoggingSeverityInfo.
+@property(nonatomic, assign) RTCLoggingSeverity severity;
+
+// The callback will be called on the same thread that does the logging, so
+// if the logging callback can be slow it may be a good idea to implement
+// dispatching to some other queue.
+- (void)start:(nullable void (^)(NSString*))callback;
+
+- (void)stop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/logging/RTCCallbackLogger.mm b/sdk/objc/api/logging/RTCCallbackLogger.mm
new file mode 100644
index 0000000..8440d63
--- /dev/null
+++ b/sdk/objc/api/logging/RTCCallbackLogger.mm
@@ -0,0 +1,92 @@
+/*
+ *  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 "RTCCallbackLogger.h"
+
+#include <memory>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/logsinks.h"
+
+class CallbackLogSink : public rtc::LogSink {
+ public:
+  CallbackLogSink(void (^callbackHandler)(NSString *message)) {
+    callback_handler_ = callbackHandler;
+  }
+
+  ~CallbackLogSink() override { callback_handler_ = nil; }
+
+  void OnLogMessage(const std::string &message) override {
+    if (callback_handler_) {
+      callback_handler_([NSString stringWithUTF8String:message.c_str()]);
+    }
+  }
+
+ private:
+  void (^callback_handler_)(NSString *message);
+};
+
+@implementation RTCCallbackLogger {
+  BOOL _hasStarted;
+  std::unique_ptr<CallbackLogSink> _logSink;
+}
+
+@synthesize severity = _severity;
+
+- (instancetype)init {
+  self = [super init];
+  if (self != nil) {
+    _severity = RTCLoggingSeverityInfo;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self stop];
+}
+
+- (void)start:(nullable void (^)(NSString *))callback {
+  if (_hasStarted) {
+    return;
+  }
+
+  _logSink.reset(new CallbackLogSink(callback));
+
+  rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]);
+  _hasStarted = YES;
+}
+
+- (void)stop {
+  if (!_hasStarted) {
+    return;
+  }
+  RTC_DCHECK(_logSink);
+  rtc::LogMessage::RemoveLogToStream(_logSink.get());
+  _hasStarted = NO;
+  _logSink.reset();
+}
+
+#pragma mark - Private
+
+- (rtc::LoggingSeverity)rtcSeverity {
+  switch (_severity) {
+    case RTCLoggingSeverityVerbose:
+      return rtc::LS_VERBOSE;
+    case RTCLoggingSeverityInfo:
+      return rtc::LS_INFO;
+    case RTCLoggingSeverityWarning:
+      return rtc::LS_WARNING;
+    case RTCLoggingSeverityError:
+      return rtc::LS_ERROR;
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCAudioSource+Private.h b/sdk/objc/api/peerconnection/RTCAudioSource+Private.h
new file mode 100644
index 0000000..bf1ea62
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioSource+Private.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2016 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 "RTCAudioSource.h"
+
+#import "RTCMediaSource+Private.h"
+
+@interface RTCAudioSource ()
+
+/**
+ * The AudioSourceInterface object passed to this RTCAudioSource during
+ * construction.
+ */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::AudioSourceInterface> nativeAudioSource;
+
+/** Initialize an RTCAudioSource from a native AudioSourceInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
+              nativeAudioSource:(rtc::scoped_refptr<webrtc::AudioSourceInterface>)nativeAudioSource
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type NS_UNAVAILABLE;
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCAudioSource.h b/sdk/objc/api/peerconnection/RTCAudioSource.h
new file mode 100644
index 0000000..f6bccc9
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioSource.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2016 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"
+#import "RTCMediaSource.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCAudioSource : RTCMediaSource
+
+- (instancetype)init NS_UNAVAILABLE;
+
+// Sets the volume for the RTCMediaSource. |volume| is a gain value in the range
+// [0, 10].
+// Temporary fix to be able to modify volume of remote audio tracks.
+// TODO(kthelgason): Property stays here temporarily until a proper volume-api
+// is available on the surface exposed by webrtc.
+@property(nonatomic, assign) double volume;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCAudioSource.mm b/sdk/objc/api/peerconnection/RTCAudioSource.mm
new file mode 100644
index 0000000..a6822f6
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioSource.mm
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 2016 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 "RTCAudioSource+Private.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCAudioSource {
+}
+
+@synthesize volume = _volume;
+@synthesize nativeAudioSource = _nativeAudioSource;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeAudioSource:
+                  (rtc::scoped_refptr<webrtc::AudioSourceInterface>)nativeAudioSource {
+  RTC_DCHECK(factory);
+  RTC_DCHECK(nativeAudioSource);
+
+  if (self = [super initWithFactory:factory
+                  nativeMediaSource:nativeAudioSource
+                               type:RTCMediaSourceTypeAudio]) {
+    _nativeAudioSource = nativeAudioSource;
+  }
+  return self;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type {
+  RTC_NOTREACHED();
+  return nil;
+}
+
+- (NSString *)description {
+  NSString *stateString = [[self class] stringForState:self.state];
+  return [NSString stringWithFormat:@"RTCAudioSource( %p ): %@", self, stateString];
+}
+
+- (void)setVolume:(double)volume {
+  _volume = volume;
+  _nativeAudioSource->SetVolume(volume);
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCAudioTrack+Private.h b/sdk/objc/api/peerconnection/RTCAudioTrack+Private.h
new file mode 100644
index 0000000..fe30d65
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioTrack+Private.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2015 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 "RTCAudioTrack.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+@interface RTCAudioTrack ()
+
+/** AudioTrackInterface created or passed in at construction. */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::AudioTrackInterface> nativeAudioTrack;
+
+/** Initialize an RTCAudioTrack with an id. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                         source:(RTCAudioSource *)source
+                        trackId:(NSString *)trackId;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCAudioTrack.h b/sdk/objc/api/peerconnection/RTCAudioTrack.h
new file mode 100644
index 0000000..4fb634f
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioTrack.h
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2015 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 "RTCMacros.h"
+#import "RTCMediaStreamTrack.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCAudioSource;
+
+RTC_EXPORT
+@interface RTCAudioTrack : RTCMediaStreamTrack
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** The audio source for this audio track. */
+@property(nonatomic, readonly) RTCAudioSource *source;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCAudioTrack.mm b/sdk/objc/api/peerconnection/RTCAudioTrack.mm
new file mode 100644
index 0000000..3389b76
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCAudioTrack.mm
@@ -0,0 +1,68 @@
+/*
+ *  Copyright 2015 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 "RTCAudioTrack+Private.h"
+
+#import "RTCAudioSource+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCPeerConnectionFactory+Private.h"
+#import "helpers/NSString+StdString.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCAudioTrack
+
+@synthesize source = _source;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                         source:(RTCAudioSource *)source
+                        trackId:(NSString *)trackId {
+  RTC_DCHECK(factory);
+  RTC_DCHECK(source);
+  RTC_DCHECK(trackId.length);
+
+  std::string nativeId = [NSString stdStringForString:trackId];
+  rtc::scoped_refptr<webrtc::AudioTrackInterface> track =
+      factory.nativeFactory->CreateAudioTrack(nativeId, source.nativeAudioSource);
+  if (self = [self initWithFactory:factory nativeTrack:track type:RTCMediaStreamTrackTypeAudio]) {
+    _source = source;
+  }
+  return self;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
+                           type:(RTCMediaStreamTrackType)type {
+  NSParameterAssert(factory);
+  NSParameterAssert(nativeTrack);
+  NSParameterAssert(type == RTCMediaStreamTrackTypeAudio);
+  return [super initWithFactory:factory nativeTrack:nativeTrack type:type];
+}
+
+
+- (RTCAudioSource *)source {
+  if (!_source) {
+    rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
+        self.nativeAudioTrack->GetSource();
+    if (source) {
+      _source =
+          [[RTCAudioSource alloc] initWithFactory:self.factory nativeAudioSource:source.get()];
+    }
+  }
+  return _source;
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::AudioTrackInterface>)nativeAudioTrack {
+  return static_cast<webrtc::AudioTrackInterface *>(self.nativeTrack.get());
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCCertificate.h b/sdk/objc/api/peerconnection/RTCCertificate.h
new file mode 100644
index 0000000..f6e9d02
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCCertificate.h
@@ -0,0 +1,44 @@
+/*
+ *  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
+
+RTC_EXPORT
+@interface RTCCertificate : NSObject <NSCopying>
+
+/** Private key in PEM. */
+@property(nonatomic, readonly, copy) NSString *private_key;
+
+/** Public key in an x509 cert encoded in PEM. */
+@property(nonatomic, readonly, copy) NSString *certificate;
+
+/**
+ * Initialize an RTCCertificate with PEM strings for private_key and certificate.
+ */
+- (instancetype)initWithPrivateKey:(NSString *)private_key
+                       certificate:(NSString *)certificate NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Generate a new certificate for 're' use.
+ *
+ *  Optional dictionary of parameters. Defaults to KeyType ECDSA if none are
+ *  provided.
+ *  - name: "ECDSA" or "RSASSA-PKCS1-v1_5"
+ */
++ (nullable RTCCertificate *)generateCertificateWithParams:(NSDictionary *)params;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCCertificate.mm b/sdk/objc/api/peerconnection/RTCCertificate.mm
new file mode 100644
index 0000000..bce4c3b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCCertificate.mm
@@ -0,0 +1,71 @@
+/*
+ *  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 "RTCCertificate.h"
+
+#import "base/RTCLogging.h"
+
+#include "rtc_base/logging.h"
+#include "rtc_base/rtccertificategenerator.h"
+#include "rtc_base/sslidentity.h"
+
+@implementation RTCCertificate
+
+@synthesize private_key = _private_key;
+@synthesize certificate = _certificate;
+
+- (id)copyWithZone:(NSZone *)zone {
+  id copy = [[[self class] alloc] initWithPrivateKey:[self.private_key copyWithZone:zone]
+                                         certificate:[self.certificate copyWithZone:zone]];
+  return copy;
+}
+
+- (instancetype)initWithPrivateKey:(NSString *)private_key certificate:(NSString *)certificate {
+  if (self = [super init]) {
+    _private_key = [private_key copy];
+    _certificate = [certificate copy];
+  }
+  return self;
+}
+
++ (nullable RTCCertificate *)generateCertificateWithParams:(NSDictionary *)params {
+  rtc::KeyType keyType = rtc::KT_ECDSA;
+  NSString *keyTypeString = [params valueForKey:@"name"];
+  if (keyTypeString && [keyTypeString isEqualToString:@"RSASSA-PKCS1-v1_5"]) {
+    keyType = rtc::KT_RSA;
+  }
+
+  NSNumber *expires = [params valueForKey:@"expires"];
+  rtc::scoped_refptr<rtc::RTCCertificate> cc_certificate = nullptr;
+  if (expires != nil) {
+    uint64_t expirationTimestamp = [expires unsignedLongLongValue];
+    cc_certificate = rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(keyType),
+                                                                       expirationTimestamp);
+  } else {
+    cc_certificate =
+        rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(keyType), absl::nullopt);
+  }
+  if (!cc_certificate) {
+    RTCLogError(@"Failed to generate certificate.");
+    return nullptr;
+  }
+  // grab PEMs and create an NS RTCCerticicate
+  rtc::RTCCertificatePEM pem = cc_certificate->ToPEM();
+  std::string pem_private_key = pem.private_key();
+  std::string pem_certificate = pem.certificate();
+  RTC_LOG(LS_INFO) << "CERT PEM ";
+  RTC_LOG(LS_INFO) << pem_certificate;
+
+  RTCCertificate *cert = [[RTCCertificate alloc] initWithPrivateKey:@(pem_private_key.c_str())
+                                                        certificate:@(pem_certificate.c_str())];
+  return cert;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration+Native.h b/sdk/objc/api/peerconnection/RTCConfiguration+Native.h
new file mode 100644
index 0000000..e14e6d4
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCConfiguration+Native.h
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCConfiguration.h"
+
+#include "api/peerconnectioninterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCConfiguration ()
+
+/** Optional TurnCustomizer.
+ *  With this class one can modify outgoing TURN messages.
+ *  The object passed in must remain valid until PeerConnection::Close() is
+ * called.
+ */
+@property(nonatomic, nullable) webrtc::TurnCustomizer* turnCustomizer;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration+Private.h b/sdk/objc/api/peerconnection/RTCConfiguration+Private.h
new file mode 100644
index 0000000..cb45441
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCConfiguration+Private.h
@@ -0,0 +1,78 @@
+/*
+ *  Copyright 2015 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 "RTCConfiguration.h"
+
+#include "api/peerconnectioninterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCConfiguration ()
+
++ (webrtc::PeerConnectionInterface::IceTransportsType)nativeTransportsTypeForTransportPolicy:
+        (RTCIceTransportPolicy)policy;
+
++ (RTCIceTransportPolicy)transportPolicyForTransportsType:
+        (webrtc::PeerConnectionInterface::IceTransportsType)nativeType;
+
++ (NSString *)stringForTransportPolicy:(RTCIceTransportPolicy)policy;
+
++ (webrtc::PeerConnectionInterface::BundlePolicy)nativeBundlePolicyForPolicy:
+        (RTCBundlePolicy)policy;
+
++ (RTCBundlePolicy)bundlePolicyForNativePolicy:
+        (webrtc::PeerConnectionInterface::BundlePolicy)nativePolicy;
+
++ (NSString *)stringForBundlePolicy:(RTCBundlePolicy)policy;
+
++ (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativeRtcpMuxPolicyForPolicy:
+        (RTCRtcpMuxPolicy)policy;
+
++ (RTCRtcpMuxPolicy)rtcpMuxPolicyForNativePolicy:
+        (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativePolicy;
+
++ (NSString *)stringForRtcpMuxPolicy:(RTCRtcpMuxPolicy)policy;
+
++ (webrtc::PeerConnectionInterface::TcpCandidatePolicy)nativeTcpCandidatePolicyForPolicy:
+        (RTCTcpCandidatePolicy)policy;
+
++ (RTCTcpCandidatePolicy)tcpCandidatePolicyForNativePolicy:
+        (webrtc::PeerConnectionInterface::TcpCandidatePolicy)nativePolicy;
+
++ (NSString *)stringForTcpCandidatePolicy:(RTCTcpCandidatePolicy)policy;
+
++ (webrtc::PeerConnectionInterface::CandidateNetworkPolicy)nativeCandidateNetworkPolicyForPolicy:
+        (RTCCandidateNetworkPolicy)policy;
+
++ (RTCCandidateNetworkPolicy)candidateNetworkPolicyForNativePolicy:
+        (webrtc::PeerConnectionInterface::CandidateNetworkPolicy)nativePolicy;
+
++ (NSString *)stringForCandidateNetworkPolicy:(RTCCandidateNetworkPolicy)policy;
+
++ (rtc::KeyType)nativeEncryptionKeyTypeForKeyType:(RTCEncryptionKeyType)keyType;
+
++ (webrtc::SdpSemantics)nativeSdpSemanticsForSdpSemantics:(RTCSdpSemantics)sdpSemantics;
+
++ (RTCSdpSemantics)sdpSemanticsForNativeSdpSemantics:(webrtc::SdpSemantics)sdpSemantics;
+
++ (NSString *)stringForSdpSemantics:(RTCSdpSemantics)sdpSemantics;
+
+/**
+ * RTCConfiguration struct representation of this RTCConfiguration. This is
+ * needed to pass to the underlying C++ APIs.
+ */
+- (nullable webrtc::PeerConnectionInterface::RTCConfiguration *)createNativeConfiguration;
+
+- (instancetype)initWithNativeConfiguration:
+        (const webrtc::PeerConnectionInterface::RTCConfiguration &)config NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.h b/sdk/objc/api/peerconnection/RTCConfiguration.h
new file mode 100644
index 0000000..bc70f0f
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCConfiguration.h
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2015 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 "RTCCertificate.h"
+#import "RTCMacros.h"
+
+@class RTCIceServer;
+@class RTCIntervalRange;
+
+/**
+ * Represents the ice transport policy. This exposes the same states in C++,
+ * which include one more state than what exists in the W3C spec.
+ */
+typedef NS_ENUM(NSInteger, RTCIceTransportPolicy) {
+  RTCIceTransportPolicyNone,
+  RTCIceTransportPolicyRelay,
+  RTCIceTransportPolicyNoHost,
+  RTCIceTransportPolicyAll
+};
+
+/** Represents the bundle policy. */
+typedef NS_ENUM(NSInteger, RTCBundlePolicy) {
+  RTCBundlePolicyBalanced,
+  RTCBundlePolicyMaxCompat,
+  RTCBundlePolicyMaxBundle
+};
+
+/** Represents the rtcp mux policy. */
+typedef NS_ENUM(NSInteger, RTCRtcpMuxPolicy) { RTCRtcpMuxPolicyNegotiate, RTCRtcpMuxPolicyRequire };
+
+/** Represents the tcp candidate policy. */
+typedef NS_ENUM(NSInteger, RTCTcpCandidatePolicy) {
+  RTCTcpCandidatePolicyEnabled,
+  RTCTcpCandidatePolicyDisabled
+};
+
+/** Represents the candidate network policy. */
+typedef NS_ENUM(NSInteger, RTCCandidateNetworkPolicy) {
+  RTCCandidateNetworkPolicyAll,
+  RTCCandidateNetworkPolicyLowCost
+};
+
+/** Represents the continual gathering policy. */
+typedef NS_ENUM(NSInteger, RTCContinualGatheringPolicy) {
+  RTCContinualGatheringPolicyGatherOnce,
+  RTCContinualGatheringPolicyGatherContinually
+};
+
+/** Represents the encryption key type. */
+typedef NS_ENUM(NSInteger, RTCEncryptionKeyType) {
+  RTCEncryptionKeyTypeRSA,
+  RTCEncryptionKeyTypeECDSA,
+};
+
+/** Represents the chosen SDP semantics for the RTCPeerConnection. */
+typedef NS_ENUM(NSInteger, RTCSdpSemantics) {
+  RTCSdpSemanticsPlanB,
+  RTCSdpSemanticsUnifiedPlan,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCConfiguration : NSObject
+
+/** An array of Ice Servers available to be used by ICE. */
+@property(nonatomic, copy) NSArray<RTCIceServer *> *iceServers;
+
+/** An RTCCertificate for 're' use. */
+@property(nonatomic, nullable) RTCCertificate *certificate;
+
+/** Which candidates the ICE agent is allowed to use. The W3C calls it
+ * |iceTransportPolicy|, while in C++ it is called |type|. */
+@property(nonatomic, assign) RTCIceTransportPolicy iceTransportPolicy;
+
+/** The media-bundling policy to use when gathering ICE candidates. */
+@property(nonatomic, assign) RTCBundlePolicy bundlePolicy;
+
+/** The rtcp-mux policy to use when gathering ICE candidates. */
+@property(nonatomic, assign) RTCRtcpMuxPolicy rtcpMuxPolicy;
+@property(nonatomic, assign) RTCTcpCandidatePolicy tcpCandidatePolicy;
+@property(nonatomic, assign) RTCCandidateNetworkPolicy candidateNetworkPolicy;
+@property(nonatomic, assign) RTCContinualGatheringPolicy continualGatheringPolicy;
+
+/** By default, the PeerConnection will use a limited number of IPv6 network
+ *  interfaces, in order to avoid too many ICE candidate pairs being created
+ *  and delaying ICE completion.
+ *
+ *  Can be set to INT_MAX to effectively disable the limit.
+ */
+@property(nonatomic, assign) int maxIPv6Networks;
+
+/** Exclude link-local network interfaces
+ *  from considertaion for gathering ICE candidates.
+ *  Defaults to NO.
+ */
+@property(nonatomic, assign) BOOL disableLinkLocalNetworks;
+
+@property(nonatomic, assign) int audioJitterBufferMaxPackets;
+@property(nonatomic, assign) BOOL audioJitterBufferFastAccelerate;
+@property(nonatomic, assign) int iceConnectionReceivingTimeout;
+@property(nonatomic, assign) int iceBackupCandidatePairPingInterval;
+
+/** Key type used to generate SSL identity. Default is ECDSA. */
+@property(nonatomic, assign) RTCEncryptionKeyType keyType;
+
+/** ICE candidate pool size as defined in JSEP. Default is 0. */
+@property(nonatomic, assign) int iceCandidatePoolSize;
+
+/** Prune turn ports on the same network to the same turn server.
+ *  Default is NO.
+ */
+@property(nonatomic, assign) BOOL shouldPruneTurnPorts;
+
+/** If set to YES, this means the ICE transport should presume TURN-to-TURN
+ *  candidate pairs will succeed, even before a binding response is received.
+ */
+@property(nonatomic, assign) BOOL shouldPresumeWritableWhenFullyRelayed;
+
+/** If set to non-nil, controls the minimal interval between consecutive ICE
+ *  check packets.
+ */
+@property(nonatomic, copy, nullable) NSNumber *iceCheckMinInterval;
+
+/** ICE Periodic Regathering
+ *  If set, WebRTC will periodically create and propose candidates without
+ *  starting a new ICE generation. The regathering happens continuously with
+ *  interval specified in milliseconds by the uniform distribution [a, b].
+ */
+@property(nonatomic, strong, nullable) RTCIntervalRange *iceRegatherIntervalRange;
+
+/** Configure the SDP semantics used by this PeerConnection. Note that the
+ *  WebRTC 1.0 specification requires UnifiedPlan semantics. The
+ *  RTCRtpTransceiver API is only available with UnifiedPlan semantics.
+ *
+ *  PlanB will cause RTCPeerConnection to create offers and answers with at
+ *  most one audio and one video m= section with multiple RTCRtpSenders and
+ *  RTCRtpReceivers specified as multiple a=ssrc lines within the section. This
+ *  will also cause RTCPeerConnection to ignore all but the first m= section of
+ *  the same media type.
+ *
+ *  UnifiedPlan will cause RTCPeerConnection to create offers and answers with
+ *  multiple m= sections where each m= section maps to one RTCRtpSender and one
+ *  RTCRtpReceiver (an RTCRtpTransceiver), either both audio or both video. This
+ *  will also cause RTCPeerConnection to ignore all but the first a=ssrc lines
+ *  that form a Plan B stream.
+ *
+ *  For users who wish to send multiple audio/video streams and need to stay
+ *  interoperable with legacy WebRTC implementations or use legacy APIs,
+ *  specify PlanB.
+ *
+ *  For all other users, specify UnifiedPlan.
+ */
+@property(nonatomic, assign) RTCSdpSemantics sdpSemantics;
+
+/** Actively reset the SRTP parameters when the DTLS transports underneath are
+ *  changed after offer/answer negotiation. This is only intended to be a
+ *  workaround for crbug.com/835958
+ */
+@property(nonatomic, assign) BOOL activeResetSrtpParams;
+
+- (instancetype)init;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCConfiguration.mm b/sdk/objc/api/peerconnection/RTCConfiguration.mm
new file mode 100644
index 0000000..31805f1
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCConfiguration.mm
@@ -0,0 +1,461 @@
+/*
+ *  Copyright 2015 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 "RTCConfiguration+Private.h"
+
+#include <memory>
+
+#import "RTCCertificate.h"
+#import "RTCConfiguration+Native.h"
+#import "RTCIceServer+Private.h"
+#import "RTCIntervalRange+Private.h"
+#import "base/RTCLogging.h"
+
+#include "rtc_base/rtccertificategenerator.h"
+#include "rtc_base/sslidentity.h"
+
+@implementation RTCConfiguration
+
+@synthesize iceServers = _iceServers;
+@synthesize certificate = _certificate;
+@synthesize iceTransportPolicy = _iceTransportPolicy;
+@synthesize bundlePolicy = _bundlePolicy;
+@synthesize rtcpMuxPolicy = _rtcpMuxPolicy;
+@synthesize tcpCandidatePolicy = _tcpCandidatePolicy;
+@synthesize candidateNetworkPolicy = _candidateNetworkPolicy;
+@synthesize continualGatheringPolicy = _continualGatheringPolicy;
+@synthesize maxIPv6Networks = _maxIPv6Networks;
+@synthesize disableLinkLocalNetworks = _disableLinkLocalNetworks;
+@synthesize audioJitterBufferMaxPackets = _audioJitterBufferMaxPackets;
+@synthesize audioJitterBufferFastAccelerate = _audioJitterBufferFastAccelerate;
+@synthesize iceConnectionReceivingTimeout = _iceConnectionReceivingTimeout;
+@synthesize iceBackupCandidatePairPingInterval =
+    _iceBackupCandidatePairPingInterval;
+@synthesize keyType = _keyType;
+@synthesize iceCandidatePoolSize = _iceCandidatePoolSize;
+@synthesize shouldPruneTurnPorts = _shouldPruneTurnPorts;
+@synthesize shouldPresumeWritableWhenFullyRelayed =
+    _shouldPresumeWritableWhenFullyRelayed;
+@synthesize iceCheckMinInterval = _iceCheckMinInterval;
+@synthesize iceRegatherIntervalRange = _iceRegatherIntervalRange;
+@synthesize sdpSemantics = _sdpSemantics;
+@synthesize turnCustomizer = _turnCustomizer;
+@synthesize activeResetSrtpParams = _activeResetSrtpParams;
+
+- (instancetype)init {
+  // Copy defaults.
+  webrtc::PeerConnectionInterface::RTCConfiguration config(
+    webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive);
+  return [self initWithNativeConfiguration:config];
+}
+
+- (instancetype)initWithNativeConfiguration:
+    (const webrtc::PeerConnectionInterface::RTCConfiguration &)config {
+  if (self = [super init]) {
+    NSMutableArray *iceServers = [NSMutableArray array];
+    for (const webrtc::PeerConnectionInterface::IceServer& server : config.servers) {
+      RTCIceServer *iceServer = [[RTCIceServer alloc] initWithNativeServer:server];
+      [iceServers addObject:iceServer];
+    }
+    _iceServers = iceServers;
+    if (!config.certificates.empty()) {
+      rtc::scoped_refptr<rtc::RTCCertificate> native_cert;
+      native_cert = config.certificates[0];
+      rtc::RTCCertificatePEM native_pem = native_cert->ToPEM();
+      _certificate =
+          [[RTCCertificate alloc] initWithPrivateKey:@(native_pem.private_key().c_str())
+                                         certificate:@(native_pem.certificate().c_str())];
+    }
+    _iceTransportPolicy =
+        [[self class] transportPolicyForTransportsType:config.type];
+    _bundlePolicy =
+        [[self class] bundlePolicyForNativePolicy:config.bundle_policy];
+    _rtcpMuxPolicy =
+        [[self class] rtcpMuxPolicyForNativePolicy:config.rtcp_mux_policy];
+    _tcpCandidatePolicy = [[self class] tcpCandidatePolicyForNativePolicy:
+        config.tcp_candidate_policy];
+    _candidateNetworkPolicy = [[self class]
+        candidateNetworkPolicyForNativePolicy:config.candidate_network_policy];
+    webrtc::PeerConnectionInterface::ContinualGatheringPolicy nativePolicy =
+    config.continual_gathering_policy;
+    _continualGatheringPolicy =
+        [[self class] continualGatheringPolicyForNativePolicy:nativePolicy];
+    _maxIPv6Networks = config.max_ipv6_networks;
+    _disableLinkLocalNetworks = config.disable_link_local_networks;
+    _audioJitterBufferMaxPackets = config.audio_jitter_buffer_max_packets;
+    _audioJitterBufferFastAccelerate = config.audio_jitter_buffer_fast_accelerate;
+    _iceConnectionReceivingTimeout = config.ice_connection_receiving_timeout;
+    _iceBackupCandidatePairPingInterval =
+        config.ice_backup_candidate_pair_ping_interval;
+    _keyType = RTCEncryptionKeyTypeECDSA;
+    _iceCandidatePoolSize = config.ice_candidate_pool_size;
+    _shouldPruneTurnPorts = config.prune_turn_ports;
+    _shouldPresumeWritableWhenFullyRelayed =
+        config.presume_writable_when_fully_relayed;
+    if (config.ice_check_min_interval) {
+      _iceCheckMinInterval =
+          [NSNumber numberWithInt:*config.ice_check_min_interval];
+    }
+    if (config.ice_regather_interval_range) {
+      const rtc::IntervalRange &nativeIntervalRange = config.ice_regather_interval_range.value();
+      _iceRegatherIntervalRange =
+          [[RTCIntervalRange alloc] initWithNativeIntervalRange:nativeIntervalRange];
+    }
+    _sdpSemantics = [[self class] sdpSemanticsForNativeSdpSemantics:config.sdp_semantics];
+    _turnCustomizer = config.turn_customizer;
+    _activeResetSrtpParams = config.active_reset_srtp_params;
+  }
+  return self;
+}
+
+- (NSString *)description {
+  static NSString *formatString =
+      @"RTCConfiguration: "
+      @"{\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%@\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%@\n%@\n%d\n%d\n%d\n}\n";
+
+  return [NSString
+      stringWithFormat:formatString,
+                       _iceServers,
+                       [[self class] stringForTransportPolicy:_iceTransportPolicy],
+                       [[self class] stringForBundlePolicy:_bundlePolicy],
+                       [[self class] stringForRtcpMuxPolicy:_rtcpMuxPolicy],
+                       [[self class] stringForTcpCandidatePolicy:_tcpCandidatePolicy],
+                       [[self class] stringForCandidateNetworkPolicy:_candidateNetworkPolicy],
+                       [[self class] stringForContinualGatheringPolicy:_continualGatheringPolicy],
+                       [[self class] stringForSdpSemantics:_sdpSemantics],
+                       _audioJitterBufferMaxPackets,
+                       _audioJitterBufferFastAccelerate,
+                       _iceConnectionReceivingTimeout,
+                       _iceBackupCandidatePairPingInterval,
+                       _iceCandidatePoolSize,
+                       _shouldPruneTurnPorts,
+                       _shouldPresumeWritableWhenFullyRelayed,
+                       _iceCheckMinInterval,
+                       _iceRegatherIntervalRange,
+                       _disableLinkLocalNetworks,
+                       _maxIPv6Networks,
+                       _activeResetSrtpParams];
+}
+
+#pragma mark - Private
+
+- (webrtc::PeerConnectionInterface::RTCConfiguration *)
+    createNativeConfiguration {
+  std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration>
+      nativeConfig(new webrtc::PeerConnectionInterface::RTCConfiguration(
+          webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive));
+
+  for (RTCIceServer *iceServer in _iceServers) {
+    nativeConfig->servers.push_back(iceServer.nativeServer);
+  }
+  nativeConfig->type =
+      [[self class] nativeTransportsTypeForTransportPolicy:_iceTransportPolicy];
+  nativeConfig->bundle_policy =
+      [[self class] nativeBundlePolicyForPolicy:_bundlePolicy];
+  nativeConfig->rtcp_mux_policy =
+      [[self class] nativeRtcpMuxPolicyForPolicy:_rtcpMuxPolicy];
+  nativeConfig->tcp_candidate_policy =
+      [[self class] nativeTcpCandidatePolicyForPolicy:_tcpCandidatePolicy];
+  nativeConfig->candidate_network_policy = [[self class]
+      nativeCandidateNetworkPolicyForPolicy:_candidateNetworkPolicy];
+  nativeConfig->continual_gathering_policy = [[self class]
+      nativeContinualGatheringPolicyForPolicy:_continualGatheringPolicy];
+  nativeConfig->max_ipv6_networks = _maxIPv6Networks;
+  nativeConfig->disable_link_local_networks = _disableLinkLocalNetworks;
+  nativeConfig->audio_jitter_buffer_max_packets = _audioJitterBufferMaxPackets;
+  nativeConfig->audio_jitter_buffer_fast_accelerate =
+      _audioJitterBufferFastAccelerate  ? true : false;
+  nativeConfig->ice_connection_receiving_timeout =
+      _iceConnectionReceivingTimeout;
+  nativeConfig->ice_backup_candidate_pair_ping_interval =
+      _iceBackupCandidatePairPingInterval;
+  rtc::KeyType keyType =
+      [[self class] nativeEncryptionKeyTypeForKeyType:_keyType];
+  if (_certificate != nullptr) {
+    // if offered a pemcert use it...
+    RTC_LOG(LS_INFO) << "Have configured cert - using it.";
+    std::string pem_private_key = [[_certificate private_key] UTF8String];
+    std::string pem_certificate = [[_certificate certificate] UTF8String];
+    rtc::RTCCertificatePEM pem = rtc::RTCCertificatePEM(pem_private_key, pem_certificate);
+    rtc::scoped_refptr<rtc::RTCCertificate> certificate = rtc::RTCCertificate::FromPEM(pem);
+    RTC_LOG(LS_INFO) << "Created cert from PEM strings.";
+    if (!certificate) {
+      RTC_LOG(LS_ERROR) << "Failed to generate certificate from PEM.";
+      return nullptr;
+    }
+    nativeConfig->certificates.push_back(certificate);
+  } else {
+    RTC_LOG(LS_INFO) << "Don't have configured cert.";
+    // Generate non-default certificate.
+    if (keyType != rtc::KT_DEFAULT) {
+      rtc::scoped_refptr<rtc::RTCCertificate> certificate =
+          rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams(keyType),
+                                                            absl::optional<uint64_t>());
+      if (!certificate) {
+        RTCLogError(@"Failed to generate certificate.");
+        return nullptr;
+      }
+      nativeConfig->certificates.push_back(certificate);
+    }
+  }
+  nativeConfig->ice_candidate_pool_size = _iceCandidatePoolSize;
+  nativeConfig->prune_turn_ports = _shouldPruneTurnPorts ? true : false;
+  nativeConfig->presume_writable_when_fully_relayed =
+      _shouldPresumeWritableWhenFullyRelayed ? true : false;
+  if (_iceCheckMinInterval != nil) {
+    nativeConfig->ice_check_min_interval = absl::optional<int>(_iceCheckMinInterval.intValue);
+  }
+  if (_iceRegatherIntervalRange != nil) {
+    std::unique_ptr<rtc::IntervalRange> nativeIntervalRange(
+        _iceRegatherIntervalRange.nativeIntervalRange);
+    nativeConfig->ice_regather_interval_range =
+        absl::optional<rtc::IntervalRange>(*nativeIntervalRange);
+  }
+  nativeConfig->sdp_semantics = [[self class] nativeSdpSemanticsForSdpSemantics:_sdpSemantics];
+  if (_turnCustomizer) {
+    nativeConfig->turn_customizer = _turnCustomizer;
+  }
+  nativeConfig->active_reset_srtp_params = _activeResetSrtpParams ? true : false;
+  return nativeConfig.release();
+}
+
++ (webrtc::PeerConnectionInterface::IceTransportsType)
+    nativeTransportsTypeForTransportPolicy:(RTCIceTransportPolicy)policy {
+  switch (policy) {
+    case RTCIceTransportPolicyNone:
+      return webrtc::PeerConnectionInterface::kNone;
+    case RTCIceTransportPolicyRelay:
+      return webrtc::PeerConnectionInterface::kRelay;
+    case RTCIceTransportPolicyNoHost:
+      return webrtc::PeerConnectionInterface::kNoHost;
+    case RTCIceTransportPolicyAll:
+      return webrtc::PeerConnectionInterface::kAll;
+  }
+}
+
++ (RTCIceTransportPolicy)transportPolicyForTransportsType:
+    (webrtc::PeerConnectionInterface::IceTransportsType)nativeType {
+  switch (nativeType) {
+    case webrtc::PeerConnectionInterface::kNone:
+      return RTCIceTransportPolicyNone;
+    case webrtc::PeerConnectionInterface::kRelay:
+      return RTCIceTransportPolicyRelay;
+    case webrtc::PeerConnectionInterface::kNoHost:
+      return RTCIceTransportPolicyNoHost;
+    case webrtc::PeerConnectionInterface::kAll:
+      return RTCIceTransportPolicyAll;
+  }
+}
+
++ (NSString *)stringForTransportPolicy:(RTCIceTransportPolicy)policy {
+  switch (policy) {
+    case RTCIceTransportPolicyNone:
+      return @"NONE";
+    case RTCIceTransportPolicyRelay:
+      return @"RELAY";
+    case RTCIceTransportPolicyNoHost:
+      return @"NO_HOST";
+    case RTCIceTransportPolicyAll:
+      return @"ALL";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::BundlePolicy)nativeBundlePolicyForPolicy:
+    (RTCBundlePolicy)policy {
+  switch (policy) {
+    case RTCBundlePolicyBalanced:
+      return webrtc::PeerConnectionInterface::kBundlePolicyBalanced;
+    case RTCBundlePolicyMaxCompat:
+      return webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat;
+    case RTCBundlePolicyMaxBundle:
+      return webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle;
+  }
+}
+
++ (RTCBundlePolicy)bundlePolicyForNativePolicy:
+    (webrtc::PeerConnectionInterface::BundlePolicy)nativePolicy {
+  switch (nativePolicy) {
+    case webrtc::PeerConnectionInterface::kBundlePolicyBalanced:
+      return RTCBundlePolicyBalanced;
+    case webrtc::PeerConnectionInterface::kBundlePolicyMaxCompat:
+      return RTCBundlePolicyMaxCompat;
+    case webrtc::PeerConnectionInterface::kBundlePolicyMaxBundle:
+      return RTCBundlePolicyMaxBundle;
+  }
+}
+
++ (NSString *)stringForBundlePolicy:(RTCBundlePolicy)policy {
+  switch (policy) {
+    case RTCBundlePolicyBalanced:
+      return @"BALANCED";
+    case RTCBundlePolicyMaxCompat:
+      return @"MAX_COMPAT";
+    case RTCBundlePolicyMaxBundle:
+      return @"MAX_BUNDLE";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativeRtcpMuxPolicyForPolicy:
+    (RTCRtcpMuxPolicy)policy {
+  switch (policy) {
+    case RTCRtcpMuxPolicyNegotiate:
+      return webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate;
+    case RTCRtcpMuxPolicyRequire:
+      return webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire;
+  }
+}
+
++ (RTCRtcpMuxPolicy)rtcpMuxPolicyForNativePolicy:
+    (webrtc::PeerConnectionInterface::RtcpMuxPolicy)nativePolicy {
+  switch (nativePolicy) {
+    case webrtc::PeerConnectionInterface::kRtcpMuxPolicyNegotiate:
+      return RTCRtcpMuxPolicyNegotiate;
+    case webrtc::PeerConnectionInterface::kRtcpMuxPolicyRequire:
+      return RTCRtcpMuxPolicyRequire;
+  }
+}
+
++ (NSString *)stringForRtcpMuxPolicy:(RTCRtcpMuxPolicy)policy {
+  switch (policy) {
+    case RTCRtcpMuxPolicyNegotiate:
+      return @"NEGOTIATE";
+    case RTCRtcpMuxPolicyRequire:
+      return @"REQUIRE";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::TcpCandidatePolicy)
+    nativeTcpCandidatePolicyForPolicy:(RTCTcpCandidatePolicy)policy {
+  switch (policy) {
+    case RTCTcpCandidatePolicyEnabled:
+      return webrtc::PeerConnectionInterface::kTcpCandidatePolicyEnabled;
+    case RTCTcpCandidatePolicyDisabled:
+      return webrtc::PeerConnectionInterface::kTcpCandidatePolicyDisabled;
+  }
+}
+
++ (webrtc::PeerConnectionInterface::CandidateNetworkPolicy)
+    nativeCandidateNetworkPolicyForPolicy:(RTCCandidateNetworkPolicy)policy {
+  switch (policy) {
+    case RTCCandidateNetworkPolicyAll:
+      return webrtc::PeerConnectionInterface::kCandidateNetworkPolicyAll;
+    case RTCCandidateNetworkPolicyLowCost:
+      return webrtc::PeerConnectionInterface::kCandidateNetworkPolicyLowCost;
+  }
+}
+
++ (RTCTcpCandidatePolicy)tcpCandidatePolicyForNativePolicy:
+    (webrtc::PeerConnectionInterface::TcpCandidatePolicy)nativePolicy {
+  switch (nativePolicy) {
+    case webrtc::PeerConnectionInterface::kTcpCandidatePolicyEnabled:
+      return RTCTcpCandidatePolicyEnabled;
+    case webrtc::PeerConnectionInterface::kTcpCandidatePolicyDisabled:
+      return RTCTcpCandidatePolicyDisabled;
+  }
+}
+
++ (NSString *)stringForTcpCandidatePolicy:(RTCTcpCandidatePolicy)policy {
+  switch (policy) {
+    case RTCTcpCandidatePolicyEnabled:
+      return @"TCP_ENABLED";
+    case RTCTcpCandidatePolicyDisabled:
+      return @"TCP_DISABLED";
+  }
+}
+
++ (RTCCandidateNetworkPolicy)candidateNetworkPolicyForNativePolicy:
+    (webrtc::PeerConnectionInterface::CandidateNetworkPolicy)nativePolicy {
+  switch (nativePolicy) {
+    case webrtc::PeerConnectionInterface::kCandidateNetworkPolicyAll:
+      return RTCCandidateNetworkPolicyAll;
+    case webrtc::PeerConnectionInterface::kCandidateNetworkPolicyLowCost:
+      return RTCCandidateNetworkPolicyLowCost;
+  }
+}
+
++ (NSString *)stringForCandidateNetworkPolicy:
+    (RTCCandidateNetworkPolicy)policy {
+  switch (policy) {
+    case RTCCandidateNetworkPolicyAll:
+      return @"CANDIDATE_ALL_NETWORKS";
+    case RTCCandidateNetworkPolicyLowCost:
+      return @"CANDIDATE_LOW_COST_NETWORKS";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::ContinualGatheringPolicy)
+    nativeContinualGatheringPolicyForPolicy:
+        (RTCContinualGatheringPolicy)policy {
+  switch (policy) {
+    case RTCContinualGatheringPolicyGatherOnce:
+      return webrtc::PeerConnectionInterface::GATHER_ONCE;
+    case RTCContinualGatheringPolicyGatherContinually:
+      return webrtc::PeerConnectionInterface::GATHER_CONTINUALLY;
+  }
+}
+
++ (RTCContinualGatheringPolicy)continualGatheringPolicyForNativePolicy:
+    (webrtc::PeerConnectionInterface::ContinualGatheringPolicy)nativePolicy {
+  switch (nativePolicy) {
+    case webrtc::PeerConnectionInterface::GATHER_ONCE:
+      return RTCContinualGatheringPolicyGatherOnce;
+    case webrtc::PeerConnectionInterface::GATHER_CONTINUALLY:
+      return RTCContinualGatheringPolicyGatherContinually;
+  }
+}
+
++ (NSString *)stringForContinualGatheringPolicy:
+    (RTCContinualGatheringPolicy)policy {
+  switch (policy) {
+    case RTCContinualGatheringPolicyGatherOnce:
+      return @"GATHER_ONCE";
+    case RTCContinualGatheringPolicyGatherContinually:
+      return @"GATHER_CONTINUALLY";
+  }
+}
+
++ (rtc::KeyType)nativeEncryptionKeyTypeForKeyType:
+    (RTCEncryptionKeyType)keyType {
+  switch (keyType) {
+    case RTCEncryptionKeyTypeRSA:
+      return rtc::KT_RSA;
+    case RTCEncryptionKeyTypeECDSA:
+      return rtc::KT_ECDSA;
+  }
+}
+
++ (webrtc::SdpSemantics)nativeSdpSemanticsForSdpSemantics:(RTCSdpSemantics)sdpSemantics {
+  switch (sdpSemantics) {
+    case RTCSdpSemanticsPlanB:
+      return webrtc::SdpSemantics::kPlanB;
+    case RTCSdpSemanticsUnifiedPlan:
+      return webrtc::SdpSemantics::kUnifiedPlan;
+  }
+}
+
++ (RTCSdpSemantics)sdpSemanticsForNativeSdpSemantics:(webrtc::SdpSemantics)sdpSemantics {
+  switch (sdpSemantics) {
+    case webrtc::SdpSemantics::kPlanB:
+      return RTCSdpSemanticsPlanB;
+    case webrtc::SdpSemantics::kUnifiedPlan:
+      return RTCSdpSemanticsUnifiedPlan;
+  }
+}
+
++ (NSString *)stringForSdpSemantics:(RTCSdpSemantics)sdpSemantics {
+  switch (sdpSemantics) {
+    case RTCSdpSemanticsPlanB:
+      return @"PLAN_B";
+    case RTCSdpSemanticsUnifiedPlan:
+      return @"UNIFIED_PLAN";
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCDataChannel+Private.h b/sdk/objc/api/peerconnection/RTCDataChannel+Private.h
new file mode 100644
index 0000000..a88a316
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannel+Private.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2015 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 "RTCDataChannel.h"
+
+#include "api/datachannelinterface.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+@interface RTCDataBuffer ()
+
+/**
+ * The native DataBuffer representation of this RTCDatabuffer object. This is
+ * needed to pass to the underlying C++ APIs.
+ */
+@property(nonatomic, readonly) const webrtc::DataBuffer *nativeDataBuffer;
+
+/** Initialize an RTCDataBuffer from a native DataBuffer. */
+- (instancetype)initWithNativeBuffer:(const webrtc::DataBuffer &)nativeBuffer;
+
+@end
+
+@interface RTCDataChannel ()
+
+/** Initialize an RTCDataChannel from a native DataChannelInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeDataChannel:(rtc::scoped_refptr<webrtc::DataChannelInterface>)nativeDataChannel
+    NS_DESIGNATED_INITIALIZER;
+
++ (webrtc::DataChannelInterface::DataState)nativeDataChannelStateForState:
+        (RTCDataChannelState)state;
+
++ (RTCDataChannelState)dataChannelStateForNativeState:
+        (webrtc::DataChannelInterface::DataState)nativeState;
+
++ (NSString *)stringForState:(RTCDataChannelState)state;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDataChannel.h b/sdk/objc/api/peerconnection/RTCDataChannel.h
new file mode 100644
index 0000000..8bde372
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannel.h
@@ -0,0 +1,130 @@
+/*
+ *  Copyright 2015 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 <AvailabilityMacros.h>
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCDataBuffer : NSObject
+
+/** NSData representation of the underlying buffer. */
+@property(nonatomic, readonly) NSData *data;
+
+/** Indicates whether |data| contains UTF-8 or binary data. */
+@property(nonatomic, readonly) BOOL isBinary;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Initialize an RTCDataBuffer from NSData. |isBinary| indicates whether |data|
+ * contains UTF-8 or binary data.
+ */
+- (instancetype)initWithData:(NSData *)data isBinary:(BOOL)isBinary;
+
+@end
+
+@class RTCDataChannel;
+RTC_EXPORT
+@protocol RTCDataChannelDelegate <NSObject>
+
+/** The data channel state changed. */
+- (void)dataChannelDidChangeState:(RTCDataChannel *)dataChannel;
+
+/** The data channel successfully received a data buffer. */
+- (void)dataChannel:(RTCDataChannel *)dataChannel
+    didReceiveMessageWithBuffer:(RTCDataBuffer *)buffer;
+
+@optional
+/** The data channel's |bufferedAmount| changed. */
+- (void)dataChannel:(RTCDataChannel *)dataChannel didChangeBufferedAmount:(uint64_t)amount;
+
+@end
+
+/** Represents the state of the data channel. */
+typedef NS_ENUM(NSInteger, RTCDataChannelState) {
+  RTCDataChannelStateConnecting,
+  RTCDataChannelStateOpen,
+  RTCDataChannelStateClosing,
+  RTCDataChannelStateClosed,
+};
+
+RTC_EXPORT
+@interface RTCDataChannel : NSObject
+
+/**
+ * A label that can be used to distinguish this data channel from other data
+ * channel objects.
+ */
+@property(nonatomic, readonly) NSString *label;
+
+/** Whether the data channel can send messages in unreliable mode. */
+@property(nonatomic, readonly) BOOL isReliable DEPRECATED_ATTRIBUTE;
+
+/** Returns whether this data channel is ordered or not. */
+@property(nonatomic, readonly) BOOL isOrdered;
+
+/** Deprecated. Use maxPacketLifeTime. */
+@property(nonatomic, readonly) NSUInteger maxRetransmitTime DEPRECATED_ATTRIBUTE;
+
+/**
+ * The length of the time window (in milliseconds) during which transmissions
+ * and retransmissions may occur in unreliable mode.
+ */
+@property(nonatomic, readonly) uint16_t maxPacketLifeTime;
+
+/**
+ * The maximum number of retransmissions that are attempted in unreliable mode.
+ */
+@property(nonatomic, readonly) uint16_t maxRetransmits;
+
+/**
+ * The name of the sub-protocol used with this data channel, if any. Otherwise
+ * this returns an empty string.
+ */
+@property(nonatomic, readonly) NSString *protocol;
+
+/**
+ * Returns whether this data channel was negotiated by the application or not.
+ */
+@property(nonatomic, readonly) BOOL isNegotiated;
+
+/** Deprecated. Use channelId. */
+@property(nonatomic, readonly) NSInteger streamId DEPRECATED_ATTRIBUTE;
+
+/** The identifier for this data channel. */
+@property(nonatomic, readonly) int channelId;
+
+/** The state of the data channel. */
+@property(nonatomic, readonly) RTCDataChannelState readyState;
+
+/**
+ * The number of bytes of application data that have been queued using
+ * |sendData:| but that have not yet been transmitted to the network.
+ */
+@property(nonatomic, readonly) uint64_t bufferedAmount;
+
+/** The delegate for this data channel. */
+@property(nonatomic, weak) id<RTCDataChannelDelegate> delegate;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Closes the data channel. */
+- (void)close;
+
+/** Attempt to send |data| on this data channel's underlying data transport. */
+- (BOOL)sendData:(RTCDataBuffer *)data;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDataChannel.mm b/sdk/objc/api/peerconnection/RTCDataChannel.mm
new file mode 100644
index 0000000..35c009e
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannel.mm
@@ -0,0 +1,223 @@
+/*
+ *  Copyright 2015 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 "RTCDataChannel+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+#include <memory>
+
+namespace webrtc {
+
+class DataChannelDelegateAdapter : public DataChannelObserver {
+ public:
+  DataChannelDelegateAdapter(RTCDataChannel *channel) { channel_ = channel; }
+
+  void OnStateChange() override {
+    [channel_.delegate dataChannelDidChangeState:channel_];
+  }
+
+  void OnMessage(const DataBuffer& buffer) override {
+    RTCDataBuffer *data_buffer =
+        [[RTCDataBuffer alloc] initWithNativeBuffer:buffer];
+    [channel_.delegate dataChannel:channel_
+       didReceiveMessageWithBuffer:data_buffer];
+  }
+
+  void OnBufferedAmountChange(uint64_t previousAmount) override {
+    id<RTCDataChannelDelegate> delegate = channel_.delegate;
+    SEL sel = @selector(dataChannel:didChangeBufferedAmount:);
+    if ([delegate respondsToSelector:sel]) {
+      [delegate dataChannel:channel_ didChangeBufferedAmount:previousAmount];
+    }
+  }
+
+ private:
+  __weak RTCDataChannel *channel_;
+};
+}
+
+
+@implementation RTCDataBuffer {
+  std::unique_ptr<webrtc::DataBuffer> _dataBuffer;
+}
+
+- (instancetype)initWithData:(NSData *)data isBinary:(BOOL)isBinary {
+  NSParameterAssert(data);
+  if (self = [super init]) {
+    rtc::CopyOnWriteBuffer buffer(
+        reinterpret_cast<const uint8_t*>(data.bytes), data.length);
+    _dataBuffer.reset(new webrtc::DataBuffer(buffer, isBinary));
+  }
+  return self;
+}
+
+- (NSData *)data {
+  return [NSData dataWithBytes:_dataBuffer->data.data()
+                        length:_dataBuffer->data.size()];
+}
+
+- (BOOL)isBinary {
+  return _dataBuffer->binary;
+}
+
+#pragma mark - Private
+
+- (instancetype)initWithNativeBuffer:(const webrtc::DataBuffer&)nativeBuffer {
+  if (self = [super init]) {
+    _dataBuffer.reset(new webrtc::DataBuffer(nativeBuffer));
+  }
+  return self;
+}
+
+- (const webrtc::DataBuffer *)nativeDataBuffer {
+  return _dataBuffer.get();
+}
+
+@end
+
+
+@implementation RTCDataChannel {
+  RTCPeerConnectionFactory *_factory;
+  rtc::scoped_refptr<webrtc::DataChannelInterface> _nativeDataChannel;
+  std::unique_ptr<webrtc::DataChannelDelegateAdapter> _observer;
+  BOOL _isObserverRegistered;
+}
+
+@synthesize delegate = _delegate;
+
+- (void)dealloc {
+  // Handles unregistering the observer properly. We need to do this because
+  // there may still be other references to the underlying data channel.
+  _nativeDataChannel->UnregisterObserver();
+}
+
+- (NSString *)label {
+  return [NSString stringForStdString:_nativeDataChannel->label()];
+}
+
+- (BOOL)isReliable {
+  return _nativeDataChannel->reliable();
+}
+
+- (BOOL)isOrdered {
+  return _nativeDataChannel->ordered();
+}
+
+- (NSUInteger)maxRetransmitTime {
+  return self.maxPacketLifeTime;
+}
+
+- (uint16_t)maxPacketLifeTime {
+  return _nativeDataChannel->maxRetransmitTime();
+}
+
+- (uint16_t)maxRetransmits {
+  return _nativeDataChannel->maxRetransmits();
+}
+
+- (NSString *)protocol {
+  return [NSString stringForStdString:_nativeDataChannel->protocol()];
+}
+
+- (BOOL)isNegotiated {
+  return _nativeDataChannel->negotiated();
+}
+
+- (NSInteger)streamId {
+  return self.channelId;
+}
+
+- (int)channelId {
+  return _nativeDataChannel->id();
+}
+
+- (RTCDataChannelState)readyState {
+  return [[self class] dataChannelStateForNativeState:
+      _nativeDataChannel->state()];
+}
+
+- (uint64_t)bufferedAmount {
+  return _nativeDataChannel->buffered_amount();
+}
+
+- (void)close {
+  _nativeDataChannel->Close();
+}
+
+- (BOOL)sendData:(RTCDataBuffer *)data {
+  return _nativeDataChannel->Send(*data.nativeDataBuffer);
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCDataChannel:\n%ld\n%@\n%@",
+                                    (long)self.channelId,
+                                    self.label,
+                                    [[self class]
+                                        stringForState:self.readyState]];
+}
+
+#pragma mark - Private
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeDataChannel:
+                  (rtc::scoped_refptr<webrtc::DataChannelInterface>)nativeDataChannel {
+  NSParameterAssert(nativeDataChannel);
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeDataChannel = nativeDataChannel;
+    _observer.reset(new webrtc::DataChannelDelegateAdapter(self));
+    _nativeDataChannel->RegisterObserver(_observer.get());
+  }
+  return self;
+}
+
++ (webrtc::DataChannelInterface::DataState)
+    nativeDataChannelStateForState:(RTCDataChannelState)state {
+  switch (state) {
+    case RTCDataChannelStateConnecting:
+      return webrtc::DataChannelInterface::DataState::kConnecting;
+    case RTCDataChannelStateOpen:
+      return webrtc::DataChannelInterface::DataState::kOpen;
+    case RTCDataChannelStateClosing:
+      return webrtc::DataChannelInterface::DataState::kClosing;
+    case RTCDataChannelStateClosed:
+      return webrtc::DataChannelInterface::DataState::kClosed;
+  }
+}
+
++ (RTCDataChannelState)dataChannelStateForNativeState:
+    (webrtc::DataChannelInterface::DataState)nativeState {
+  switch (nativeState) {
+    case webrtc::DataChannelInterface::DataState::kConnecting:
+      return RTCDataChannelStateConnecting;
+    case webrtc::DataChannelInterface::DataState::kOpen:
+      return RTCDataChannelStateOpen;
+    case webrtc::DataChannelInterface::DataState::kClosing:
+      return RTCDataChannelStateClosing;
+    case webrtc::DataChannelInterface::DataState::kClosed:
+      return RTCDataChannelStateClosed;
+  }
+}
+
++ (NSString *)stringForState:(RTCDataChannelState)state {
+  switch (state) {
+    case RTCDataChannelStateConnecting:
+      return @"Connecting";
+    case RTCDataChannelStateOpen:
+      return @"Open";
+    case RTCDataChannelStateClosing:
+      return @"Closing";
+    case RTCDataChannelStateClosed:
+      return @"Closed";
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCDataChannelConfiguration+Private.h b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration+Private.h
new file mode 100644
index 0000000..11be5a6
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration+Private.h
@@ -0,0 +1,23 @@
+/*
+ *  Copyright 2015 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 "RTCDataChannelConfiguration.h"
+
+#include "api/datachannelinterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCDataChannelConfiguration ()
+
+@property(nonatomic, readonly) webrtc::DataChannelInit nativeDataChannelInit;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.h b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.h
new file mode 100644
index 0000000..de4b72a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 2015 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 <AvailabilityMacros.h>
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCDataChannelConfiguration : NSObject
+
+/** Set to YES if ordered delivery is required. */
+@property(nonatomic, assign) BOOL isOrdered;
+
+/** Deprecated. Use maxPacketLifeTime. */
+@property(nonatomic, assign) NSInteger maxRetransmitTimeMs DEPRECATED_ATTRIBUTE;
+
+/**
+ * Max period in milliseconds in which retransmissions will be sent. After this
+ * time, no more retransmissions will be sent. -1 if unset.
+ */
+@property(nonatomic, assign) int maxPacketLifeTime;
+
+/** The max number of retransmissions. -1 if unset. */
+@property(nonatomic, assign) int maxRetransmits;
+
+/** Set to YES if the channel has been externally negotiated and we do not send
+ * an in-band signalling in the form of an "open" message.
+ */
+@property(nonatomic, assign) BOOL isNegotiated;
+
+/** Deprecated. Use channelId. */
+@property(nonatomic, assign) int streamId DEPRECATED_ATTRIBUTE;
+
+/** The id of the data channel. */
+@property(nonatomic, assign) int channelId;
+
+/** Set by the application and opaque to the WebRTC implementation. */
+@property(nonatomic) NSString* protocol;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.mm b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.mm
new file mode 100644
index 0000000..1208b6d
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDataChannelConfiguration.mm
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 2015 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 "RTCDataChannelConfiguration+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCDataChannelConfiguration
+
+@synthesize nativeDataChannelInit = _nativeDataChannelInit;
+
+- (BOOL)isOrdered {
+  return _nativeDataChannelInit.ordered;
+}
+
+- (void)setIsOrdered:(BOOL)isOrdered {
+  _nativeDataChannelInit.ordered = isOrdered;
+}
+
+- (NSInteger)maxRetransmitTimeMs {
+  return self.maxPacketLifeTime;
+}
+
+- (void)setMaxRetransmitTimeMs:(NSInteger)maxRetransmitTimeMs {
+  self.maxPacketLifeTime = maxRetransmitTimeMs;
+}
+
+- (int)maxPacketLifeTime {
+  return _nativeDataChannelInit.maxRetransmitTime;
+}
+
+- (void)setMaxPacketLifeTime:(int)maxPacketLifeTime {
+  _nativeDataChannelInit.maxRetransmitTime = maxPacketLifeTime;
+}
+
+- (int)maxRetransmits {
+  return _nativeDataChannelInit.maxRetransmits;
+}
+
+- (void)setMaxRetransmits:(int)maxRetransmits {
+  _nativeDataChannelInit.maxRetransmits = maxRetransmits;
+}
+
+- (NSString *)protocol {
+  return [NSString stringForStdString:_nativeDataChannelInit.protocol];
+}
+
+- (void)setProtocol:(NSString *)protocol {
+  _nativeDataChannelInit.protocol = [NSString stdStringForString:protocol];
+}
+
+- (BOOL)isNegotiated {
+  return _nativeDataChannelInit.negotiated;
+}
+
+- (void)setIsNegotiated:(BOOL)isNegotiated {
+  _nativeDataChannelInit.negotiated = isNegotiated;
+}
+
+- (int)streamId {
+  return self.channelId;
+}
+
+- (void)setStreamId:(int)streamId {
+  self.channelId = streamId;
+}
+
+- (int)channelId {
+  return _nativeDataChannelInit.id;
+}
+
+- (void)setChannelId:(int)channelId {
+  _nativeDataChannelInit.id = channelId;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCDtmfSender+Private.h b/sdk/objc/api/peerconnection/RTCDtmfSender+Private.h
new file mode 100644
index 0000000..cdcf62c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDtmfSender+Private.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCDtmfSender.h"
+
+#include "api/dtmfsenderinterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCDtmfSender : NSObject <RTCDtmfSender>
+
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::DtmfSenderInterface> nativeDtmfSender;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initialize an RTCDtmfSender with a native DtmfSenderInterface. */
+- (instancetype)initWithNativeDtmfSender:
+        (rtc::scoped_refptr<webrtc::DtmfSenderInterface>)nativeDtmfSender NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDtmfSender.h b/sdk/objc/api/peerconnection/RTCDtmfSender.h
new file mode 100644
index 0000000..1beed5c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDtmfSender.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@protocol RTCDtmfSender <NSObject>
+
+/**
+ * Returns true if this RTCDtmfSender is capable of sending DTMF. Otherwise
+ * returns false. To be able to send DTMF, the associated RTCRtpSender must be
+ * able to send packets, and a "telephone-event" codec must be negotiated.
+ */
+@property(nonatomic, readonly) BOOL canInsertDtmf;
+
+/**
+ * Queues a task that sends the DTMF tones. The tones parameter is treated
+ * as a series of characters. The characters 0 through 9, A through D, #, and *
+ * generate the associated DTMF tones. The characters a to d are equivalent
+ * to A to D. The character ',' indicates a delay of 2 seconds before
+ * processing the next character in the tones parameter.
+ *
+ * Unrecognized characters are ignored.
+ *
+ * @param duration The parameter indicates the duration to use for each
+ * character passed in the tones parameter. The duration cannot be more
+ * than 6000 or less than 70 ms.
+ *
+ * @param interToneGap The parameter indicates the gap between tones.
+ * This parameter must be at least 50 ms but should be as short as
+ * possible.
+ *
+ * If InsertDtmf is called on the same object while an existing task for this
+ * object to generate DTMF is still running, the previous task is canceled.
+ * Returns true on success and false on failure.
+ */
+- (BOOL)insertDtmf:(nonnull NSString *)tones
+          duration:(NSTimeInterval)duration
+      interToneGap:(NSTimeInterval)interToneGap;
+
+/** The tones remaining to be played out */
+- (nonnull NSString *)remainingTones;
+
+/**
+ * The current tone duration value. This value will be the value last set via the
+ * insertDtmf method, or the default value of 100 ms if insertDtmf was never called.
+ */
+- (NSTimeInterval)duration;
+
+/**
+ * The current value of the between-tone gap. This value will be the value last set
+ * via the insertDtmf() method, or the default value of 50 ms if insertDtmf() was never
+ * called.
+ */
+- (NSTimeInterval)interToneGap;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCDtmfSender.mm b/sdk/objc/api/peerconnection/RTCDtmfSender.mm
new file mode 100644
index 0000000..1513840
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCDtmfSender.mm
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCDtmfSender+Private.h"
+
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include "rtc_base/timeutils.h"
+
+@implementation RTCDtmfSender {
+  rtc::scoped_refptr<webrtc::DtmfSenderInterface> _nativeDtmfSender;
+}
+
+- (BOOL)canInsertDtmf {
+  return _nativeDtmfSender->CanInsertDtmf();
+}
+
+- (BOOL)insertDtmf:(nonnull NSString *)tones
+          duration:(NSTimeInterval)duration
+      interToneGap:(NSTimeInterval)interToneGap {
+  RTC_DCHECK(tones != nil);
+
+  int durationMs = static_cast<int>(duration * rtc::kNumMillisecsPerSec);
+  int interToneGapMs = static_cast<int>(interToneGap * rtc::kNumMillisecsPerSec);
+  return _nativeDtmfSender->InsertDtmf(
+      [NSString stdStringForString:tones], durationMs, interToneGapMs);
+}
+
+- (nonnull NSString *)remainingTones {
+  return [NSString stringForStdString:_nativeDtmfSender->tones()];
+}
+
+- (NSTimeInterval)duration {
+  return static_cast<NSTimeInterval>(_nativeDtmfSender->duration()) / rtc::kNumMillisecsPerSec;
+}
+
+- (NSTimeInterval)interToneGap {
+  return static_cast<NSTimeInterval>(_nativeDtmfSender->inter_tone_gap()) /
+      rtc::kNumMillisecsPerSec;
+}
+
+- (NSString *)description {
+  return [NSString
+      stringWithFormat:
+          @"RTCDtmfSender {\n  remainingTones: %@\n  duration: %f sec\n  interToneGap: %f sec\n}",
+          [self remainingTones],
+          [self duration],
+          [self interToneGap]];
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::DtmfSenderInterface>)nativeDtmfSender {
+  return _nativeDtmfSender;
+}
+
+- (instancetype)initWithNativeDtmfSender:
+        (rtc::scoped_refptr<webrtc::DtmfSenderInterface>)nativeDtmfSender {
+  NSParameterAssert(nativeDtmfSender);
+  if (self = [super init]) {
+    _nativeDtmfSender = nativeDtmfSender;
+    RTCLogInfo(@"RTCDtmfSender(%p): created DTMF sender: %@", self, self.description);
+  }
+  return self;
+}
+@end
diff --git a/sdk/objc/api/peerconnection/RTCEncodedImage+Private.h b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.h
new file mode 100644
index 0000000..1b125f1
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "base/RTCEncodedImage.h"
+
+#include "common_video/include/video_frame.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/* Interfaces for converting to/from internal C++ formats. */
+@interface RTCEncodedImage (Private)
+
+- (instancetype)initWithNativeEncodedImage:(webrtc::EncodedImage)encodedImage;
+- (webrtc::EncodedImage)nativeEncodedImage;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm
new file mode 100644
index 0000000..6f2d1f4
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCEncodedImage+Private.mm
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCEncodedImage+Private.h"
+
+#include "rtc_base/numerics/safe_conversions.h"
+
+@implementation RTCEncodedImage (Private)
+
+- (instancetype)initWithNativeEncodedImage:(webrtc::EncodedImage)encodedImage {
+  if (self = [super init]) {
+    // Wrap the buffer in NSData without copying, do not take ownership.
+    self.buffer = [NSData dataWithBytesNoCopy:encodedImage._buffer
+                                   length:encodedImage._length
+                             freeWhenDone:NO];
+    self.encodedWidth = rtc::dchecked_cast<int32_t>(encodedImage._encodedWidth);
+    self.encodedHeight = rtc::dchecked_cast<int32_t>(encodedImage._encodedHeight);
+    self.timeStamp = encodedImage.Timestamp();
+    self.captureTimeMs = encodedImage.capture_time_ms_;
+    self.ntpTimeMs = encodedImage.ntp_time_ms_;
+    self.flags = encodedImage.timing_.flags;
+    self.encodeStartMs = encodedImage.timing_.encode_start_ms;
+    self.encodeFinishMs = encodedImage.timing_.encode_finish_ms;
+    self.frameType = static_cast<RTCFrameType>(encodedImage._frameType);
+    self.rotation = static_cast<RTCVideoRotation>(encodedImage.rotation_);
+    self.completeFrame = encodedImage._completeFrame;
+    self.qp = @(encodedImage.qp_);
+    self.contentType = (encodedImage.content_type_ == webrtc::VideoContentType::SCREENSHARE) ?
+        RTCVideoContentTypeScreenshare :
+        RTCVideoContentTypeUnspecified;
+  }
+
+  return self;
+}
+
+- (webrtc::EncodedImage)nativeEncodedImage {
+  // Return the pointer without copying.
+  webrtc::EncodedImage encodedImage(
+      (uint8_t *)self.buffer.bytes, (size_t)self.buffer.length, (size_t)self.buffer.length);
+  encodedImage._encodedWidth = rtc::dchecked_cast<uint32_t>(self.encodedWidth);
+  encodedImage._encodedHeight = rtc::dchecked_cast<uint32_t>(self.encodedHeight);
+  encodedImage.SetTimestamp(self.timeStamp);
+  encodedImage.capture_time_ms_ = self.captureTimeMs;
+  encodedImage.ntp_time_ms_ = self.ntpTimeMs;
+  encodedImage.timing_.flags = self.flags;
+  encodedImage.timing_.encode_start_ms = self.encodeStartMs;
+  encodedImage.timing_.encode_finish_ms = self.encodeFinishMs;
+  encodedImage._frameType = webrtc::FrameType(self.frameType);
+  encodedImage.rotation_ = webrtc::VideoRotation(self.rotation);
+  encodedImage._completeFrame = self.completeFrame;
+  encodedImage.qp_ = self.qp ? self.qp.intValue : -1;
+  encodedImage.content_type_ = (self.contentType == RTCVideoContentTypeScreenshare) ?
+      webrtc::VideoContentType::SCREENSHARE :
+      webrtc::VideoContentType::UNSPECIFIED;
+
+  return encodedImage;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCFieldTrials.h b/sdk/objc/api/peerconnection/RTCFieldTrials.h
new file mode 100644
index 0000000..9b7f41c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCFieldTrials.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2016 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"
+
+/** The only valid value for the following if set is kRTCFieldTrialEnabledValue. */
+RTC_EXTERN NSString * const kRTCFieldTrialAudioSendSideBweKey;
+RTC_EXTERN NSString * const kRTCFieldTrialAudioSendSideBweForVideoKey;
+RTC_EXTERN NSString * const kRTCFieldTrialAudioForceNoTWCCKey;
+RTC_EXTERN NSString * const kRTCFieldTrialAudioForceABWENoTWCCKey;
+RTC_EXTERN NSString * const kRTCFieldTrialSendSideBweWithOverheadKey;
+RTC_EXTERN NSString * const kRTCFieldTrialFlexFec03AdvertisedKey;
+RTC_EXTERN NSString * const kRTCFieldTrialFlexFec03Key;
+RTC_EXTERN NSString * const kRTCFieldTrialImprovedBitrateEstimateKey;
+RTC_EXTERN NSString * const kRTCFieldTrialH264HighProfileKey;
+RTC_EXTERN NSString * const kRTCFieldTrialMinimizeResamplingOnMobileKey;
+
+/** The valid value for field trials above. */
+RTC_EXTERN NSString * const kRTCFieldTrialEnabledValue;
+
+/** Use a string returned by RTCFieldTrialMedianSlopeFilterValue as the value. */
+RTC_EXTERN NSString * const kRTCFieldTrialMedianSlopeFilterKey;
+RTC_EXTERN NSString *RTCFieldTrialMedianSlopeFilterValue(
+    size_t windowSize, double thresholdGain);
+
+/** Use a string returned by RTCFieldTrialTrendlineFilterValue as the value. */
+RTC_EXTERN NSString * const kRTCFieldTrialTrendlineFilterKey;
+/** Returns a valid value for kRTCFieldTrialTrendlineFilterKey. */
+RTC_EXTERN NSString *RTCFieldTrialTrendlineFilterValue(
+    size_t windowSize, double smoothingCoeff, double thresholdGain);
+
+/** Initialize field trials using a dictionary mapping field trial keys to their values. See above
+ *  for valid keys and values.
+ *  Must be called before any other call into WebRTC. See:
+ *  webrtc/system_wrappers/include/field_trial_default.h
+ */
+RTC_EXTERN void RTCInitFieldTrialDictionary(NSDictionary<NSString *, NSString *> *fieldTrials);
diff --git a/sdk/objc/api/peerconnection/RTCFieldTrials.mm b/sdk/objc/api/peerconnection/RTCFieldTrials.mm
new file mode 100644
index 0000000..c81bc55
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCFieldTrials.mm
@@ -0,0 +1,72 @@
+/*
+ *  Copyright 2016 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 "RTCFieldTrials.h"
+
+#include <memory>
+
+#import "base/RTCLogging.h"
+
+// Adding 'nogncheck' to disable the gn include headers check.
+// We don't want to depend on 'system_wrappers:field_trial_default' because
+// clients should be able to provide their own implementation.
+#include "system_wrappers/include/field_trial_default.h"  // nogncheck
+
+NSString * const kRTCFieldTrialAudioSendSideBweKey = @"WebRTC-Audio-SendSideBwe";
+NSString * const kRTCFieldTrialAudioSendSideBweForVideoKey = @"WebRTC-Audio-SendSideBwe-For-Video";
+NSString * const kRTCFieldTrialAudioForceNoTWCCKey = @"WebRTC-Audio-ForceNoTWCC";
+NSString * const kRTCFieldTrialAudioForceABWENoTWCCKey = @"WebRTC-Audio-ABWENoTWCC";
+NSString * const kRTCFieldTrialSendSideBweWithOverheadKey = @"WebRTC-SendSideBwe-WithOverhead";
+NSString * const kRTCFieldTrialFlexFec03AdvertisedKey = @"WebRTC-FlexFEC-03-Advertised";
+NSString * const kRTCFieldTrialFlexFec03Key = @"WebRTC-FlexFEC-03";
+NSString * const kRTCFieldTrialImprovedBitrateEstimateKey = @"WebRTC-ImprovedBitrateEstimate";
+NSString * const kRTCFieldTrialMedianSlopeFilterKey = @"WebRTC-BweMedianSlopeFilter";
+NSString * const kRTCFieldTrialTrendlineFilterKey = @"WebRTC-BweTrendlineFilter";
+NSString * const kRTCFieldTrialH264HighProfileKey = @"WebRTC-H264HighProfile";
+NSString * const kRTCFieldTrialMinimizeResamplingOnMobileKey =
+    @"WebRTC-Audio-MinimizeResamplingOnMobile";
+NSString * const kRTCFieldTrialEnabledValue = @"Enabled";
+
+static std::unique_ptr<char[]> gFieldTrialInitString;
+
+NSString *RTCFieldTrialMedianSlopeFilterValue(
+    size_t windowSize, double thresholdGain) {
+  NSString *format = @"Enabled-%zu,%lf";
+  return [NSString stringWithFormat:format, windowSize, thresholdGain];
+}
+
+NSString *RTCFieldTrialTrendlineFilterValue(
+    size_t windowSize, double smoothingCoeff, double thresholdGain) {
+  NSString *format = @"Enabled-%zu,%lf,%lf";
+  return [NSString stringWithFormat:format, windowSize, smoothingCoeff, thresholdGain];
+}
+
+void RTCInitFieldTrialDictionary(NSDictionary<NSString *, NSString *> *fieldTrials) {
+  if (!fieldTrials) {
+    RTCLogWarning(@"No fieldTrials provided.");
+    return;
+  }
+  // Assemble the keys and values into the field trial string.
+  // We don't perform any extra format checking. That should be done by the underlying WebRTC calls.
+  NSMutableString *fieldTrialInitString = [NSMutableString string];
+  for (NSString *key in fieldTrials) {
+    NSString *fieldTrialEntry = [NSString stringWithFormat:@"%@/%@/", key, fieldTrials[key]];
+    [fieldTrialInitString appendString:fieldTrialEntry];
+  }
+  size_t len = fieldTrialInitString.length + 1;
+  gFieldTrialInitString.reset(new char[len]);
+  if (![fieldTrialInitString getCString:gFieldTrialInitString.get()
+                              maxLength:len
+                               encoding:NSUTF8StringEncoding]) {
+    RTCLogError(@"Failed to convert field trial string.");
+    return;
+  }
+  webrtc::field_trial::InitFieldTrialsFromString(gFieldTrialInitString.get());
+}
diff --git a/sdk/objc/api/peerconnection/RTCFileLogger.h b/sdk/objc/api/peerconnection/RTCFileLogger.h
new file mode 100644
index 0000000..36b0f75
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCFileLogger.h
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2015 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"
+
+typedef NS_ENUM(NSUInteger, RTCFileLoggerSeverity) {
+  RTCFileLoggerSeverityVerbose,
+  RTCFileLoggerSeverityInfo,
+  RTCFileLoggerSeverityWarning,
+  RTCFileLoggerSeverityError
+};
+
+typedef NS_ENUM(NSUInteger, RTCFileLoggerRotationType) {
+  RTCFileLoggerTypeCall,
+  RTCFileLoggerTypeApp,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+// This class intercepts WebRTC logs and saves them to a file. The file size
+// will not exceed the given maximum bytesize. When the maximum bytesize is
+// reached, logs are rotated according to the rotationType specified.
+// For kRTCFileLoggerTypeCall, logs from the beginning and the end
+// are preserved while the middle section is overwritten instead.
+// For kRTCFileLoggerTypeApp, the oldest log is overwritten.
+// This class is not threadsafe.
+RTC_EXPORT
+@interface RTCFileLogger : NSObject
+
+// The severity level to capture. The default is kRTCFileLoggerSeverityInfo.
+@property(nonatomic, assign) RTCFileLoggerSeverity severity;
+
+// The rotation type for this file logger. The default is
+// kRTCFileLoggerTypeCall.
+@property(nonatomic, readonly) RTCFileLoggerRotationType rotationType;
+
+// Disables buffering disk writes. Should be set before |start|. Buffering
+// is enabled by default for performance.
+@property(nonatomic, assign) BOOL shouldDisableBuffering;
+
+// Default constructor provides default settings for dir path, file size and
+// rotation type.
+- (instancetype)init;
+
+// Create file logger with default rotation type.
+- (instancetype)initWithDirPath:(NSString *)dirPath maxFileSize:(NSUInteger)maxFileSize;
+
+- (instancetype)initWithDirPath:(NSString *)dirPath
+                    maxFileSize:(NSUInteger)maxFileSize
+                   rotationType:(RTCFileLoggerRotationType)rotationType NS_DESIGNATED_INITIALIZER;
+
+// Starts writing WebRTC logs to disk if not already started. Overwrites any
+// existing file(s).
+- (void)start;
+
+// Stops writing WebRTC logs to disk. This method is also called on dealloc.
+- (void)stop;
+
+// Returns the current contents of the logs, or nil if start has been called
+// without a stop.
+- (nullable NSData *)logData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCFileLogger.mm b/sdk/objc/api/peerconnection/RTCFileLogger.mm
new file mode 100644
index 0000000..3a7144a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCFileLogger.mm
@@ -0,0 +1,175 @@
+/*
+ *  Copyright 2015 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 "RTCFileLogger.h"
+
+#include <memory>
+
+#include "rtc_base/checks.h"
+#include "rtc_base/filerotatingstream.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/logsinks.h"
+
+NSString *const kDefaultLogDirName = @"webrtc_logs";
+NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB.
+const char *kRTCFileLoggerRotatingLogPrefix = "rotating_log";
+
+@implementation RTCFileLogger {
+  BOOL _hasStarted;
+  NSString *_dirPath;
+  NSUInteger _maxFileSize;
+  std::unique_ptr<rtc::FileRotatingLogSink> _logSink;
+}
+
+@synthesize severity = _severity;
+@synthesize rotationType = _rotationType;
+@synthesize shouldDisableBuffering = _shouldDisableBuffering;
+
+- (instancetype)init {
+  NSArray *paths = NSSearchPathForDirectoriesInDomains(
+      NSDocumentDirectory, NSUserDomainMask, YES);
+  NSString *documentsDirPath = [paths firstObject];
+  NSString *defaultDirPath =
+      [documentsDirPath stringByAppendingPathComponent:kDefaultLogDirName];
+  return [self initWithDirPath:defaultDirPath
+                   maxFileSize:kDefaultMaxFileSize];
+}
+
+- (instancetype)initWithDirPath:(NSString *)dirPath
+                    maxFileSize:(NSUInteger)maxFileSize {
+  return [self initWithDirPath:dirPath
+                   maxFileSize:maxFileSize
+                  rotationType:RTCFileLoggerTypeCall];
+}
+
+- (instancetype)initWithDirPath:(NSString *)dirPath
+                    maxFileSize:(NSUInteger)maxFileSize
+                   rotationType:(RTCFileLoggerRotationType)rotationType {
+  NSParameterAssert(dirPath.length);
+  NSParameterAssert(maxFileSize);
+  if (self = [super init]) {
+    BOOL isDir = NO;
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    if ([fileManager fileExistsAtPath:dirPath isDirectory:&isDir]) {
+      if (!isDir) {
+        // Bail if something already exists there.
+        return nil;
+      }
+    } else {
+      if (![fileManager createDirectoryAtPath:dirPath
+                  withIntermediateDirectories:NO
+                                   attributes:nil
+                                        error:nil]) {
+        // Bail if we failed to create a directory.
+        return nil;
+      }
+    }
+    _dirPath = dirPath;
+    _maxFileSize = maxFileSize;
+    _severity = RTCFileLoggerSeverityInfo;
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [self stop];
+}
+
+- (void)start {
+  if (_hasStarted) {
+    return;
+  }
+  switch (_rotationType) {
+    case RTCFileLoggerTypeApp:
+      _logSink.reset(
+          new rtc::FileRotatingLogSink(_dirPath.UTF8String,
+                                       kRTCFileLoggerRotatingLogPrefix,
+                                       _maxFileSize,
+                                       _maxFileSize / 10));
+      break;
+    case RTCFileLoggerTypeCall:
+      _logSink.reset(
+          new rtc::CallSessionFileRotatingLogSink(_dirPath.UTF8String,
+                                                  _maxFileSize));
+      break;
+  }
+  if (!_logSink->Init()) {
+    RTC_LOG(LS_ERROR) << "Failed to open log files at path: " << _dirPath.UTF8String;
+    _logSink.reset();
+    return;
+  }
+  if (_shouldDisableBuffering) {
+    _logSink->DisableBuffering();
+  }
+  rtc::LogMessage::LogThreads(true);
+  rtc::LogMessage::LogTimestamps(true);
+  rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]);
+  _hasStarted = YES;
+}
+
+- (void)stop {
+  if (!_hasStarted) {
+    return;
+  }
+  RTC_DCHECK(_logSink);
+  rtc::LogMessage::RemoveLogToStream(_logSink.get());
+  _hasStarted = NO;
+  _logSink.reset();
+}
+
+- (nullable NSData *)logData {
+  if (_hasStarted) {
+    return nil;
+  }
+  NSMutableData* logData = [NSMutableData data];
+  std::unique_ptr<rtc::FileRotatingStream> stream;
+  switch(_rotationType) {
+    case RTCFileLoggerTypeApp:
+      stream.reset(
+          new rtc::FileRotatingStream(_dirPath.UTF8String,
+                                      kRTCFileLoggerRotatingLogPrefix));
+      break;
+    case RTCFileLoggerTypeCall:
+      stream.reset(new rtc::CallSessionFileRotatingStream(_dirPath.UTF8String));
+      break;
+  }
+  if (!stream->Open()) {
+    return logData;
+  }
+  size_t bufferSize = 0;
+  if (!stream->GetSize(&bufferSize) || bufferSize == 0) {
+    return logData;
+  }
+  size_t read = 0;
+  // Allocate memory using malloc so we can pass it direcly to NSData without
+  // copying.
+  std::unique_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(bufferSize)));
+  stream->ReadAll(buffer.get(), bufferSize, &read, nullptr);
+  logData = [[NSMutableData alloc] initWithBytesNoCopy:buffer.release()
+                                                length:read];
+  return logData;
+}
+
+#pragma mark - Private
+
+- (rtc::LoggingSeverity)rtcSeverity {
+  switch (_severity) {
+    case RTCFileLoggerSeverityVerbose:
+      return rtc::LS_VERBOSE;
+    case RTCFileLoggerSeverityInfo:
+      return rtc::LS_INFO;
+    case RTCFileLoggerSeverityWarning:
+      return rtc::LS_WARNING;
+    case RTCFileLoggerSeverityError:
+      return rtc::LS_ERROR;
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCIceCandidate+Private.h b/sdk/objc/api/peerconnection/RTCIceCandidate+Private.h
new file mode 100644
index 0000000..8c9156c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceCandidate+Private.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright 2015 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 "RTCIceCandidate.h"
+
+#include <memory>
+
+#include "api/jsep.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCIceCandidate ()
+
+/**
+ * The native IceCandidateInterface representation of this RTCIceCandidate
+ * object. This is needed to pass to the underlying C++ APIs.
+ */
+@property(nonatomic, readonly) std::unique_ptr<webrtc::IceCandidateInterface> nativeCandidate;
+
+/**
+ * Initialize an RTCIceCandidate from a native IceCandidateInterface. No
+ * ownership is taken of the native candidate.
+ */
+- (instancetype)initWithNativeCandidate:(const webrtc::IceCandidateInterface *)candidate;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIceCandidate.h b/sdk/objc/api/peerconnection/RTCIceCandidate.h
new file mode 100644
index 0000000..7c72e56
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceCandidate.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2015 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
+
+RTC_EXPORT
+@interface RTCIceCandidate : NSObject
+
+/**
+ * If present, the identifier of the "media stream identification" for the media
+ * component this candidate is associated with.
+ */
+@property(nonatomic, readonly, nullable) NSString *sdpMid;
+
+/**
+ * The index (starting at zero) of the media description this candidate is
+ * associated with in the SDP.
+ */
+@property(nonatomic, readonly) int sdpMLineIndex;
+
+/** The SDP string for this candidate. */
+@property(nonatomic, readonly) NSString *sdp;
+
+/** The URL of the ICE server which this candidate is gathered from. */
+@property(nonatomic, readonly, nullable) NSString *serverUrl;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Initialize an RTCIceCandidate from SDP.
+ */
+- (instancetype)initWithSdp:(NSString *)sdp
+              sdpMLineIndex:(int)sdpMLineIndex
+                     sdpMid:(nullable NSString *)sdpMid NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIceCandidate.mm b/sdk/objc/api/peerconnection/RTCIceCandidate.mm
new file mode 100644
index 0000000..cbae3f3
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceCandidate.mm
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 2015 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 "RTCIceCandidate+Private.h"
+
+#include <memory>
+
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCIceCandidate
+
+@synthesize sdpMid = _sdpMid;
+@synthesize sdpMLineIndex = _sdpMLineIndex;
+@synthesize sdp = _sdp;
+@synthesize serverUrl = _serverUrl;
+
+- (instancetype)initWithSdp:(NSString *)sdp
+              sdpMLineIndex:(int)sdpMLineIndex
+                     sdpMid:(NSString *)sdpMid {
+  NSParameterAssert(sdp.length);
+  if (self = [super init]) {
+    _sdpMid = [sdpMid copy];
+    _sdpMLineIndex = sdpMLineIndex;
+    _sdp = [sdp copy];
+  }
+  return self;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCIceCandidate:\n%@\n%d\n%@\n%@",
+                                    _sdpMid,
+                                    _sdpMLineIndex,
+                                    _sdp,
+                                    _serverUrl];
+}
+
+#pragma mark - Private
+
+- (instancetype)initWithNativeCandidate:
+    (const webrtc::IceCandidateInterface *)candidate {
+  NSParameterAssert(candidate);
+  std::string sdp;
+  candidate->ToString(&sdp);
+
+  RTCIceCandidate *rtcCandidate =
+      [self initWithSdp:[NSString stringForStdString:sdp]
+          sdpMLineIndex:candidate->sdp_mline_index()
+                 sdpMid:[NSString stringForStdString:candidate->sdp_mid()]];
+  rtcCandidate->_serverUrl = [NSString stringForStdString:candidate->server_url()];
+  return rtcCandidate;
+}
+
+- (std::unique_ptr<webrtc::IceCandidateInterface>)nativeCandidate {
+  webrtc::SdpParseError error;
+
+  webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
+      _sdpMid.stdString, _sdpMLineIndex, _sdp.stdString, &error);
+
+  if (!candidate) {
+    RTCLog(@"Failed to create ICE candidate: %s\nline: %s",
+           error.description.c_str(),
+           error.line.c_str());
+  }
+
+  return std::unique_ptr<webrtc::IceCandidateInterface>(candidate);
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCIceServer+Private.h b/sdk/objc/api/peerconnection/RTCIceServer+Private.h
new file mode 100644
index 0000000..8d16dfd
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceServer+Private.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2015 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 "RTCIceServer.h"
+
+#include "api/peerconnectioninterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCIceServer ()
+
+/**
+ * IceServer struct representation of this RTCIceServer object's data.
+ * This is needed to pass to the underlying C++ APIs.
+ */
+@property(nonatomic, readonly) webrtc::PeerConnectionInterface::IceServer nativeServer;
+
+/** Initialize an RTCIceServer from a native IceServer. */
+- (instancetype)initWithNativeServer:(webrtc::PeerConnectionInterface::IceServer)nativeServer;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIceServer.h b/sdk/objc/api/peerconnection/RTCIceServer.h
new file mode 100644
index 0000000..c2def04
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceServer.h
@@ -0,0 +1,114 @@
+/*
+ *  Copyright 2015 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"
+
+typedef NS_ENUM(NSUInteger, RTCTlsCertPolicy) {
+  RTCTlsCertPolicySecure,
+  RTCTlsCertPolicyInsecureNoCheck
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCIceServer : NSObject
+
+/** URI(s) for this server represented as NSStrings. */
+@property(nonatomic, readonly) NSArray<NSString *> *urlStrings;
+
+/** Username to use if this RTCIceServer object is a TURN server. */
+@property(nonatomic, readonly, nullable) NSString *username;
+
+/** Credential to use if this RTCIceServer object is a TURN server. */
+@property(nonatomic, readonly, nullable) NSString *credential;
+
+/**
+ * TLS certificate policy to use if this RTCIceServer object is a TURN server.
+ */
+@property(nonatomic, readonly) RTCTlsCertPolicy tlsCertPolicy;
+
+/**
+  If the URIs in |urls| only contain IP addresses, this field can be used
+  to indicate the hostname, which may be necessary for TLS (using the SNI
+  extension). If |urls| itself contains the hostname, this isn't necessary.
+ */
+@property(nonatomic, readonly, nullable) NSString *hostname;
+
+/** List of protocols to be used in the TLS ALPN extension. */
+@property(nonatomic, readonly) NSArray<NSString *> *tlsAlpnProtocols;
+
+/**
+  List elliptic curves to be used in the TLS elliptic curves extension.
+  Only curve names supported by OpenSSL should be used (eg. "P-256","X25519").
+  */
+@property(nonatomic, readonly) NSArray<NSString *> *tlsEllipticCurves;
+
+- (nonnull instancetype)init NS_UNAVAILABLE;
+
+/** Convenience initializer for a server with no authentication (e.g. STUN). */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings;
+
+/**
+ * Initialize an RTCIceServer with its associated URLs, optional username,
+ * optional credential, and credentialType.
+ */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(nullable NSString *)username
+                        credential:(nullable NSString *)credential;
+
+/**
+ * Initialize an RTCIceServer with its associated URLs, optional username,
+ * optional credential, and TLS cert policy.
+ */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(nullable NSString *)username
+                        credential:(nullable NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy;
+
+/**
+ * Initialize an RTCIceServer with its associated URLs, optional username,
+ * optional credential, TLS cert policy and hostname.
+ */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(nullable NSString *)username
+                        credential:(nullable NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(nullable NSString *)hostname;
+
+/**
+ * Initialize an RTCIceServer with its associated URLs, optional username,
+ * optional credential, TLS cert policy, hostname and ALPN protocols.
+ */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(nullable NSString *)username
+                        credential:(nullable NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(nullable NSString *)hostname
+                  tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols;
+
+/**
+ * Initialize an RTCIceServer with its associated URLs, optional username,
+ * optional credential, TLS cert policy, hostname, ALPN protocols and
+ * elliptic curves.
+ */
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(nullable NSString *)username
+                        credential:(nullable NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(nullable NSString *)hostname
+                  tlsAlpnProtocols:(nullable NSArray<NSString *> *)tlsAlpnProtocols
+                 tlsEllipticCurves:(nullable NSArray<NSString *> *)tlsEllipticCurves
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIceServer.mm b/sdk/objc/api/peerconnection/RTCIceServer.mm
new file mode 100644
index 0000000..2138e4c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIceServer.mm
@@ -0,0 +1,196 @@
+/*
+ *  Copyright 2015 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 "RTCIceServer+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCIceServer
+
+@synthesize urlStrings = _urlStrings;
+@synthesize username = _username;
+@synthesize credential = _credential;
+@synthesize tlsCertPolicy = _tlsCertPolicy;
+@synthesize hostname = _hostname;
+@synthesize tlsAlpnProtocols = _tlsAlpnProtocols;
+@synthesize tlsEllipticCurves = _tlsEllipticCurves;
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings {
+  return [self initWithURLStrings:urlStrings
+                         username:nil
+                       credential:nil];
+}
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(NSString *)username
+                        credential:(NSString *)credential {
+  return [self initWithURLStrings:urlStrings
+                         username:username
+                       credential:credential
+                    tlsCertPolicy:RTCTlsCertPolicySecure];
+}
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(NSString *)username
+                        credential:(NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy {
+  return [self initWithURLStrings:urlStrings
+                         username:username
+                       credential:credential
+                    tlsCertPolicy:tlsCertPolicy
+                         hostname:nil];
+}
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(NSString *)username
+                        credential:(NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(NSString *)hostname {
+  return [self initWithURLStrings:urlStrings
+                         username:username
+                       credential:credential
+                    tlsCertPolicy:tlsCertPolicy
+                         hostname:hostname
+                 tlsAlpnProtocols:[NSArray array]];
+}
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(NSString *)username
+                        credential:(NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(NSString *)hostname
+                  tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols {
+  return [self initWithURLStrings:urlStrings
+                         username:username
+                       credential:credential
+                    tlsCertPolicy:tlsCertPolicy
+                         hostname:hostname
+                 tlsAlpnProtocols:tlsAlpnProtocols
+                tlsEllipticCurves:[NSArray array]];
+}
+
+- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
+                          username:(NSString *)username
+                        credential:(NSString *)credential
+                     tlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy
+                          hostname:(NSString *)hostname
+                  tlsAlpnProtocols:(NSArray<NSString *> *)tlsAlpnProtocols
+                 tlsEllipticCurves:(NSArray<NSString *> *)tlsEllipticCurves {
+  NSParameterAssert(urlStrings.count);
+  if (self = [super init]) {
+    _urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES];
+    _username = [username copy];
+    _credential = [credential copy];
+    _tlsCertPolicy = tlsCertPolicy;
+    _hostname = [hostname copy];
+    _tlsAlpnProtocols = [[NSArray alloc] initWithArray:tlsAlpnProtocols copyItems:YES];
+    _tlsEllipticCurves = [[NSArray alloc] initWithArray:tlsEllipticCurves copyItems:YES];
+  }
+  return self;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@\n%@\n%@\n%@\n%@",
+                                    _urlStrings,
+                                    _username,
+                                    _credential,
+                                    [self stringForTlsCertPolicy:_tlsCertPolicy],
+                                    _hostname,
+                                    _tlsAlpnProtocols,
+                                    _tlsEllipticCurves];
+}
+
+#pragma mark - Private
+
+- (NSString *)stringForTlsCertPolicy:(RTCTlsCertPolicy)tlsCertPolicy {
+  switch (tlsCertPolicy) {
+    case RTCTlsCertPolicySecure:
+      return @"RTCTlsCertPolicySecure";
+    case RTCTlsCertPolicyInsecureNoCheck:
+      return @"RTCTlsCertPolicyInsecureNoCheck";
+  }
+}
+
+- (webrtc::PeerConnectionInterface::IceServer)nativeServer {
+  __block webrtc::PeerConnectionInterface::IceServer iceServer;
+
+  iceServer.username = [NSString stdStringForString:_username];
+  iceServer.password = [NSString stdStringForString:_credential];
+  iceServer.hostname = [NSString stdStringForString:_hostname];
+
+  [_tlsAlpnProtocols enumerateObjectsUsingBlock:^(NSString *proto, NSUInteger idx, BOOL *stop) {
+    iceServer.tls_alpn_protocols.push_back(proto.stdString);
+  }];
+
+  [_tlsEllipticCurves enumerateObjectsUsingBlock:^(NSString *curve, NSUInteger idx, BOOL *stop) {
+    iceServer.tls_elliptic_curves.push_back(curve.stdString);
+  }];
+
+  [_urlStrings enumerateObjectsUsingBlock:^(NSString *url,
+                                            NSUInteger idx,
+                                            BOOL *stop) {
+    iceServer.urls.push_back(url.stdString);
+  }];
+
+  switch (_tlsCertPolicy) {
+    case RTCTlsCertPolicySecure:
+      iceServer.tls_cert_policy =
+          webrtc::PeerConnectionInterface::kTlsCertPolicySecure;
+      break;
+    case RTCTlsCertPolicyInsecureNoCheck:
+      iceServer.tls_cert_policy =
+          webrtc::PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck;
+      break;
+  }
+  return iceServer;
+}
+
+- (instancetype)initWithNativeServer:
+    (webrtc::PeerConnectionInterface::IceServer)nativeServer {
+  NSMutableArray *urls =
+      [NSMutableArray arrayWithCapacity:nativeServer.urls.size()];
+  for (auto const &url : nativeServer.urls) {
+    [urls addObject:[NSString stringForStdString:url]];
+  }
+  NSString *username = [NSString stringForStdString:nativeServer.username];
+  NSString *credential = [NSString stringForStdString:nativeServer.password];
+  NSString *hostname = [NSString stringForStdString:nativeServer.hostname];
+  NSMutableArray *tlsAlpnProtocols =
+      [NSMutableArray arrayWithCapacity:nativeServer.tls_alpn_protocols.size()];
+  for (auto const &proto : nativeServer.tls_alpn_protocols) {
+    [tlsAlpnProtocols addObject:[NSString stringForStdString:proto]];
+  }
+  NSMutableArray *tlsEllipticCurves =
+      [NSMutableArray arrayWithCapacity:nativeServer.tls_elliptic_curves.size()];
+  for (auto const &curve : nativeServer.tls_elliptic_curves) {
+    [tlsEllipticCurves addObject:[NSString stringForStdString:curve]];
+  }
+  RTCTlsCertPolicy tlsCertPolicy;
+
+  switch (nativeServer.tls_cert_policy) {
+    case webrtc::PeerConnectionInterface::kTlsCertPolicySecure:
+      tlsCertPolicy = RTCTlsCertPolicySecure;
+      break;
+    case webrtc::PeerConnectionInterface::kTlsCertPolicyInsecureNoCheck:
+      tlsCertPolicy = RTCTlsCertPolicyInsecureNoCheck;
+      break;
+  }
+
+  self = [self initWithURLStrings:urls
+                         username:username
+                       credential:credential
+                    tlsCertPolicy:tlsCertPolicy
+                         hostname:hostname
+                 tlsAlpnProtocols:tlsAlpnProtocols
+                tlsEllipticCurves:tlsEllipticCurves];
+  return self;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCIntervalRange+Private.h b/sdk/objc/api/peerconnection/RTCIntervalRange+Private.h
new file mode 100644
index 0000000..a4e59cd
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIntervalRange+Private.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCIntervalRange.h"
+
+#include "rtc_base/timeutils.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCIntervalRange ()
+
+@property(nonatomic, readonly) std::unique_ptr<rtc::IntervalRange> nativeIntervalRange;
+
+- (instancetype)initWithNativeIntervalRange:(const rtc::IntervalRange &)config;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIntervalRange.h b/sdk/objc/api/peerconnection/RTCIntervalRange.h
new file mode 100644
index 0000000..00508eb
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIntervalRange.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCIntervalRange : NSObject
+
+@property(nonatomic, readonly) NSInteger min;
+@property(nonatomic, readonly) NSInteger max;
+
+- (instancetype)init;
+- (instancetype)initWithMin:(NSInteger)min max:(NSInteger)max NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCIntervalRange.mm b/sdk/objc/api/peerconnection/RTCIntervalRange.mm
new file mode 100644
index 0000000..0a861ea
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCIntervalRange.mm
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCIntervalRange+Private.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCIntervalRange
+
+@synthesize min = _min;
+@synthesize max = _max;
+
+- (instancetype)init {
+  return [self initWithMin:0 max:0];
+}
+
+- (instancetype)initWithMin:(NSInteger)min
+                        max:(NSInteger)max {
+  RTC_DCHECK_LE(min, max);
+  if (self = [super init]) {
+    _min = min;
+    _max = max;
+  }
+  return self;
+}
+
+- (instancetype)initWithNativeIntervalRange:(const rtc::IntervalRange &)config {
+  return [self initWithMin:config.min() max:config.max()];
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"[%ld, %ld]", (long)_min, (long)_max];
+}
+
+#pragma mark - Private
+
+- (std::unique_ptr<rtc::IntervalRange>)nativeIntervalRange {
+  std::unique_ptr<rtc::IntervalRange> nativeIntervalRange(
+      new rtc::IntervalRange((int)_min, (int)_max));
+  return nativeIntervalRange;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCLegacyStatsReport+Private.h b/sdk/objc/api/peerconnection/RTCLegacyStatsReport+Private.h
new file mode 100644
index 0000000..51888b6
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCLegacyStatsReport+Private.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright 2015 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 "RTCLegacyStatsReport.h"
+
+#include "api/statstypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCLegacyStatsReport ()
+
+/** Initialize an RTCLegacyStatsReport object from a native StatsReport. */
+- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCLegacyStatsReport.h b/sdk/objc/api/peerconnection/RTCLegacyStatsReport.h
new file mode 100644
index 0000000..5ea9ff5
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCLegacyStatsReport.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2015 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
+
+/** This does not currently conform to the spec. */
+RTC_EXPORT
+@interface RTCLegacyStatsReport : NSObject
+
+/** Time since 1970-01-01T00:00:00Z in milliseconds. */
+@property(nonatomic, readonly) CFTimeInterval timestamp;
+
+/** The type of stats held by this object. */
+@property(nonatomic, readonly) NSString *type;
+
+/** The identifier for this object. */
+@property(nonatomic, readonly) NSString *reportId;
+
+/** A dictionary holding the actual stats. */
+@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *values;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCLegacyStatsReport.mm b/sdk/objc/api/peerconnection/RTCLegacyStatsReport.mm
new file mode 100644
index 0000000..89e1b85
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCLegacyStatsReport.mm
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2015 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 "RTCLegacyStatsReport+Private.h"
+
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCLegacyStatsReport
+
+@synthesize timestamp = _timestamp;
+@synthesize type = _type;
+@synthesize reportId = _reportId;
+@synthesize values = _values;
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCLegacyStatsReport:\n%@\n%@\n%f\n%@",
+                                    _reportId,
+                                    _type,
+                                    _timestamp,
+                                    _values];
+}
+
+#pragma mark - Private
+
+- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport {
+  if (self = [super init]) {
+    _timestamp = nativeReport.timestamp();
+    _type = [NSString stringForStdString:nativeReport.TypeToString()];
+    _reportId = [NSString stringForStdString:
+        nativeReport.id()->ToString()];
+
+    NSUInteger capacity = nativeReport.values().size();
+    NSMutableDictionary *values =
+        [NSMutableDictionary dictionaryWithCapacity:capacity];
+    for (auto const &valuePair : nativeReport.values()) {
+      NSString *key = [NSString stringForStdString:
+          valuePair.second->display_name()];
+      NSString *value = [NSString stringForStdString:
+          valuePair.second->ToString()];
+
+      // Not expecting duplicate keys.
+      RTC_DCHECK(![values objectForKey:key]);
+      [values setObject:value forKey:key];
+    }
+    _values = values;
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCMediaConstraints+Private.h b/sdk/objc/api/peerconnection/RTCMediaConstraints+Private.h
new file mode 100644
index 0000000..68a9436
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaConstraints+Private.h
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 2015 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 "RTCMediaConstraints.h"
+
+#include <memory>
+
+#include "api/mediaconstraintsinterface.h"
+
+namespace webrtc {
+
+class MediaConstraints : public MediaConstraintsInterface {
+ public:
+  ~MediaConstraints() override;
+  MediaConstraints();
+  MediaConstraints(const MediaConstraintsInterface::Constraints& mandatory,
+                   const MediaConstraintsInterface::Constraints& optional);
+  const Constraints& GetMandatory() const override;
+  const Constraints& GetOptional() const override;
+
+ private:
+  MediaConstraintsInterface::Constraints mandatory_;
+  MediaConstraintsInterface::Constraints optional_;
+};
+
+}  // namespace webrtc
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCMediaConstraints ()
+
+/**
+ * A MediaConstraints representation of this RTCMediaConstraints object. This is
+ * needed to pass to the underlying C++ APIs.
+ */
+- (std::unique_ptr<webrtc::MediaConstraints>)nativeConstraints;
+
+/** Return a native Constraints object representing these constraints */
++ (webrtc::MediaConstraintsInterface::Constraints)nativeConstraintsForConstraints:
+        (NSDictionary<NSString*, NSString*>*)constraints;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaConstraints.h b/sdk/objc/api/peerconnection/RTCMediaConstraints.h
new file mode 100644
index 0000000..adde356
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaConstraints.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2015 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
+
+/** Constraint keys for media sources. */
+RTC_EXTERN NSString *const kRTCMediaConstraintsMinAspectRatio;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMaxAspectRatio;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMaxWidth;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMinWidth;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMaxHeight;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMinHeight;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMaxFrameRate;
+RTC_EXTERN NSString *const kRTCMediaConstraintsMinFrameRate;
+/** The value for this key should be a base64 encoded string containing
+ *  the data from the serialized configuration proto.
+ */
+RTC_EXTERN NSString *const kRTCMediaConstraintsAudioNetworkAdaptorConfig;
+
+/** Constraint keys for generating offers and answers. */
+RTC_EXTERN NSString *const kRTCMediaConstraintsIceRestart;
+RTC_EXTERN NSString *const kRTCMediaConstraintsOfferToReceiveAudio;
+RTC_EXTERN NSString *const kRTCMediaConstraintsOfferToReceiveVideo;
+RTC_EXTERN NSString *const kRTCMediaConstraintsVoiceActivityDetection;
+
+/** Constraint values for Boolean parameters. */
+RTC_EXTERN NSString *const kRTCMediaConstraintsValueTrue;
+RTC_EXTERN NSString *const kRTCMediaConstraintsValueFalse;
+
+RTC_EXPORT
+@interface RTCMediaConstraints : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initialize with mandatory and/or optional constraints. */
+- (instancetype)
+    initWithMandatoryConstraints:(nullable NSDictionary<NSString *, NSString *> *)mandatory
+             optionalConstraints:(nullable NSDictionary<NSString *, NSString *> *)optional
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaConstraints.mm b/sdk/objc/api/peerconnection/RTCMediaConstraints.mm
new file mode 100644
index 0000000..a45486f
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaConstraints.mm
@@ -0,0 +1,136 @@
+/*
+ *  Copyright 2015 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 "RTCMediaConstraints+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+#include <memory>
+
+NSString * const kRTCMediaConstraintsMinAspectRatio =
+    @(webrtc::MediaConstraintsInterface::kMinAspectRatio);
+NSString * const kRTCMediaConstraintsMaxAspectRatio =
+    @(webrtc::MediaConstraintsInterface::kMaxAspectRatio);
+NSString * const kRTCMediaConstraintsMinWidth =
+    @(webrtc::MediaConstraintsInterface::kMinWidth);
+NSString * const kRTCMediaConstraintsMaxWidth =
+    @(webrtc::MediaConstraintsInterface::kMaxWidth);
+NSString * const kRTCMediaConstraintsMinHeight =
+    @(webrtc::MediaConstraintsInterface::kMinHeight);
+NSString * const kRTCMediaConstraintsMaxHeight =
+    @(webrtc::MediaConstraintsInterface::kMaxHeight);
+NSString * const kRTCMediaConstraintsMinFrameRate =
+    @(webrtc::MediaConstraintsInterface::kMinFrameRate);
+NSString * const kRTCMediaConstraintsMaxFrameRate =
+    @(webrtc::MediaConstraintsInterface::kMaxFrameRate);
+NSString * const kRTCMediaConstraintsAudioNetworkAdaptorConfig =
+    @(webrtc::MediaConstraintsInterface::kAudioNetworkAdaptorConfig);
+
+NSString * const kRTCMediaConstraintsIceRestart =
+    @(webrtc::MediaConstraintsInterface::kIceRestart);
+NSString * const kRTCMediaConstraintsOfferToReceiveAudio =
+    @(webrtc::MediaConstraintsInterface::kOfferToReceiveAudio);
+NSString * const kRTCMediaConstraintsOfferToReceiveVideo =
+    @(webrtc::MediaConstraintsInterface::kOfferToReceiveVideo);
+NSString * const kRTCMediaConstraintsVoiceActivityDetection =
+    @(webrtc::MediaConstraintsInterface::kVoiceActivityDetection);
+
+NSString * const kRTCMediaConstraintsValueTrue =
+    @(webrtc::MediaConstraintsInterface::kValueTrue);
+NSString * const kRTCMediaConstraintsValueFalse =
+    @(webrtc::MediaConstraintsInterface::kValueFalse);
+
+namespace webrtc {
+
+MediaConstraints::~MediaConstraints() {}
+
+MediaConstraints::MediaConstraints() {}
+
+MediaConstraints::MediaConstraints(
+    const MediaConstraintsInterface::Constraints& mandatory,
+    const MediaConstraintsInterface::Constraints& optional)
+    : mandatory_(mandatory), optional_(optional) {}
+
+const MediaConstraintsInterface::Constraints&
+MediaConstraints::GetMandatory() const {
+  return mandatory_;
+}
+
+const MediaConstraintsInterface::Constraints&
+MediaConstraints::GetOptional() const {
+  return optional_;
+}
+
+}  // namespace webrtc
+
+
+@implementation RTCMediaConstraints {
+  NSDictionary<NSString *, NSString *> *_mandatory;
+  NSDictionary<NSString *, NSString *> *_optional;
+}
+
+- (instancetype)initWithMandatoryConstraints:
+    (NSDictionary<NSString *, NSString *> *)mandatory
+                         optionalConstraints:
+    (NSDictionary<NSString *, NSString *> *)optional {
+  if (self = [super init]) {
+    _mandatory = [[NSDictionary alloc] initWithDictionary:mandatory
+                                                copyItems:YES];
+    _optional = [[NSDictionary alloc] initWithDictionary:optional
+                                               copyItems:YES];
+  }
+  return self;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCMediaConstraints:\n%@\n%@",
+                                    _mandatory,
+                                    _optional];
+}
+
+#pragma mark - Private
+
+- (std::unique_ptr<webrtc::MediaConstraints>)nativeConstraints {
+  webrtc::MediaConstraintsInterface::Constraints mandatory =
+      [[self class] nativeConstraintsForConstraints:_mandatory];
+  webrtc::MediaConstraintsInterface::Constraints optional =
+      [[self class] nativeConstraintsForConstraints:_optional];
+
+  webrtc::MediaConstraints *nativeConstraints =
+      new webrtc::MediaConstraints(mandatory, optional);
+  return std::unique_ptr<webrtc::MediaConstraints>(nativeConstraints);
+}
+
++ (webrtc::MediaConstraintsInterface::Constraints)
+    nativeConstraintsForConstraints:
+        (NSDictionary<NSString *, NSString *> *)constraints {
+  webrtc::MediaConstraintsInterface::Constraints nativeConstraints;
+  for (NSString *key in constraints) {
+    NSAssert([key isKindOfClass:[NSString class]],
+             @"%@ is not an NSString.", key);
+    NSString *value = [constraints objectForKey:key];
+    NSAssert([value isKindOfClass:[NSString class]],
+             @"%@ is not an NSString.", value);
+    if ([kRTCMediaConstraintsAudioNetworkAdaptorConfig isEqualToString:key]) {
+      // This value is base64 encoded.
+      NSData *charData = [[NSData alloc] initWithBase64EncodedString:value options:0];
+      std::string configValue =
+          std::string(reinterpret_cast<const char *>(charData.bytes), charData.length);
+      nativeConstraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
+          key.stdString, configValue));
+    } else {
+      nativeConstraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
+          key.stdString, value.stdString));
+    }
+  }
+  return nativeConstraints;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCMediaSource+Private.h b/sdk/objc/api/peerconnection/RTCMediaSource+Private.h
new file mode 100644
index 0000000..a34cbbd
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaSource+Private.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2016 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 "RTCMediaSource.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+typedef NS_ENUM(NSInteger, RTCMediaSourceType) {
+  RTCMediaSourceTypeAudio,
+  RTCMediaSourceTypeVideo,
+};
+
+@interface RTCMediaSource ()
+
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::MediaSourceInterface> nativeMediaSource;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type NS_DESIGNATED_INITIALIZER;
+
++ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:(RTCSourceState)state;
+
++ (RTCSourceState)sourceStateForNativeState:(webrtc::MediaSourceInterface::SourceState)nativeState;
+
++ (NSString *)stringForState:(RTCSourceState)state;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaSource.h b/sdk/objc/api/peerconnection/RTCMediaSource.h
new file mode 100644
index 0000000..9a1137a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaSource.h
@@ -0,0 +1,34 @@
+/*
+ *  Copyright 2016 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"
+
+typedef NS_ENUM(NSInteger, RTCSourceState) {
+  RTCSourceStateInitializing,
+  RTCSourceStateLive,
+  RTCSourceStateEnded,
+  RTCSourceStateMuted,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCMediaSource : NSObject
+
+/** The current state of the RTCMediaSource. */
+@property(nonatomic, readonly) RTCSourceState state;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaSource.mm b/sdk/objc/api/peerconnection/RTCMediaSource.mm
new file mode 100644
index 0000000..6ec41c3
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaSource.mm
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 2016 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 "RTCMediaSource+Private.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCMediaSource {
+  RTCPeerConnectionFactory *_factory;
+  RTCMediaSourceType _type;
+}
+
+@synthesize nativeMediaSource = _nativeMediaSource;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type {
+  RTC_DCHECK(factory);
+  RTC_DCHECK(nativeMediaSource);
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeMediaSource = nativeMediaSource;
+    _type = type;
+  }
+  return self;
+}
+
+- (RTCSourceState)state {
+  return [[self class] sourceStateForNativeState:_nativeMediaSource->state()];
+}
+
+#pragma mark - Private
+
++ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
+    (RTCSourceState)state {
+  switch (state) {
+    case RTCSourceStateInitializing:
+      return webrtc::MediaSourceInterface::kInitializing;
+    case RTCSourceStateLive:
+      return webrtc::MediaSourceInterface::kLive;
+    case RTCSourceStateEnded:
+      return webrtc::MediaSourceInterface::kEnded;
+    case RTCSourceStateMuted:
+      return webrtc::MediaSourceInterface::kMuted;
+  }
+}
+
++ (RTCSourceState)sourceStateForNativeState:
+    (webrtc::MediaSourceInterface::SourceState)nativeState {
+  switch (nativeState) {
+    case webrtc::MediaSourceInterface::kInitializing:
+      return RTCSourceStateInitializing;
+    case webrtc::MediaSourceInterface::kLive:
+      return RTCSourceStateLive;
+    case webrtc::MediaSourceInterface::kEnded:
+      return RTCSourceStateEnded;
+    case webrtc::MediaSourceInterface::kMuted:
+      return RTCSourceStateMuted;
+  }
+}
+
++ (NSString *)stringForState:(RTCSourceState)state {
+  switch (state) {
+    case RTCSourceStateInitializing:
+      return @"Initializing";
+    case RTCSourceStateLive:
+      return @"Live";
+    case RTCSourceStateEnded:
+      return @"Ended";
+    case RTCSourceStateMuted:
+      return @"Muted";
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCMediaStream+Private.h b/sdk/objc/api/peerconnection/RTCMediaStream+Private.h
new file mode 100644
index 0000000..21d64ec
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStream+Private.h
@@ -0,0 +1,34 @@
+/*
+ *  Copyright 2015 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 "RTCMediaStream.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCMediaStream ()
+
+/**
+ * MediaStreamInterface representation of this RTCMediaStream object. This is
+ * needed to pass to the underlying C++ APIs.
+ */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::MediaStreamInterface> nativeMediaStream;
+
+/** Initialize an RTCMediaStream with an id. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory streamId:(NSString *)streamId;
+
+/** Initialize an RTCMediaStream from a native MediaStreamInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaStream:(rtc::scoped_refptr<webrtc::MediaStreamInterface>)nativeMediaStream;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaStream.h b/sdk/objc/api/peerconnection/RTCMediaStream.h
new file mode 100644
index 0000000..675e4b9
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStream.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2015 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
+
+@class RTCAudioTrack;
+@class RTCPeerConnectionFactory;
+@class RTCVideoTrack;
+
+RTC_EXPORT
+@interface RTCMediaStream : NSObject
+
+/** The audio tracks in this stream. */
+@property(nonatomic, strong, readonly) NSArray<RTCAudioTrack *> *audioTracks;
+
+/** The video tracks in this stream. */
+@property(nonatomic, strong, readonly) NSArray<RTCVideoTrack *> *videoTracks;
+
+/** An identifier for this media stream. */
+@property(nonatomic, readonly) NSString *streamId;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Adds the given audio track to this media stream. */
+- (void)addAudioTrack:(RTCAudioTrack *)audioTrack;
+
+/** Adds the given video track to this media stream. */
+- (void)addVideoTrack:(RTCVideoTrack *)videoTrack;
+
+/** Removes the given audio track to this media stream. */
+- (void)removeAudioTrack:(RTCAudioTrack *)audioTrack;
+
+/** Removes the given video track to this media stream. */
+- (void)removeVideoTrack:(RTCVideoTrack *)videoTrack;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaStream.mm b/sdk/objc/api/peerconnection/RTCMediaStream.mm
new file mode 100644
index 0000000..c1a402a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStream.mm
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 2015 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 "RTCMediaStream+Private.h"
+
+#include <vector>
+
+#import "RTCAudioTrack+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCPeerConnectionFactory+Private.h"
+#import "RTCVideoTrack+Private.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCMediaStream {
+  RTCPeerConnectionFactory *_factory;
+  NSMutableArray *_audioTracks;
+  NSMutableArray *_videoTracks;
+  rtc::scoped_refptr<webrtc::MediaStreamInterface> _nativeMediaStream;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                       streamId:(NSString *)streamId {
+  NSParameterAssert(factory);
+  NSParameterAssert(streamId.length);
+  std::string nativeId = [NSString stdStringForString:streamId];
+  rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
+      factory.nativeFactory->CreateLocalMediaStream(nativeId);
+  return [self initWithFactory:factory nativeMediaStream:stream];
+}
+
+- (NSArray<RTCAudioTrack *> *)audioTracks {
+  return [_audioTracks copy];
+}
+
+- (NSArray<RTCVideoTrack *> *)videoTracks {
+  return [_videoTracks copy];
+}
+
+- (NSString *)streamId {
+  return [NSString stringForStdString:_nativeMediaStream->id()];
+}
+
+- (void)addAudioTrack:(RTCAudioTrack *)audioTrack {
+  if (_nativeMediaStream->AddTrack(audioTrack.nativeAudioTrack)) {
+    [_audioTracks addObject:audioTrack];
+  }
+}
+
+- (void)addVideoTrack:(RTCVideoTrack *)videoTrack {
+  if (_nativeMediaStream->AddTrack(videoTrack.nativeVideoTrack)) {
+    [_videoTracks addObject:videoTrack];
+  }
+}
+
+- (void)removeAudioTrack:(RTCAudioTrack *)audioTrack {
+  NSUInteger index = [_audioTracks indexOfObjectIdenticalTo:audioTrack];
+  NSAssert(index != NSNotFound,
+           @"|removeAudioTrack| called on unexpected RTCAudioTrack");
+  if (index != NSNotFound &&
+      _nativeMediaStream->RemoveTrack(audioTrack.nativeAudioTrack)) {
+    [_audioTracks removeObjectAtIndex:index];
+  }
+}
+
+- (void)removeVideoTrack:(RTCVideoTrack *)videoTrack {
+  NSUInteger index = [_videoTracks indexOfObjectIdenticalTo:videoTrack];
+  NSAssert(index != NSNotFound,
+           @"|removeVideoTrack| called on unexpected RTCVideoTrack");
+  if (index != NSNotFound &&
+      _nativeMediaStream->RemoveTrack(videoTrack.nativeVideoTrack)) {
+    [_videoTracks removeObjectAtIndex:index];
+  }
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCMediaStream:\n%@\nA=%lu\nV=%lu",
+                                    self.streamId,
+                                    (unsigned long)self.audioTracks.count,
+                                    (unsigned long)self.videoTracks.count];
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::MediaStreamInterface>)nativeMediaStream {
+  return _nativeMediaStream;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaStream:
+                  (rtc::scoped_refptr<webrtc::MediaStreamInterface>)nativeMediaStream {
+  NSParameterAssert(nativeMediaStream);
+  if (self = [super init]) {
+    _factory = factory;
+
+    webrtc::AudioTrackVector audioTracks = nativeMediaStream->GetAudioTracks();
+    webrtc::VideoTrackVector videoTracks = nativeMediaStream->GetVideoTracks();
+
+    _audioTracks = [NSMutableArray arrayWithCapacity:audioTracks.size()];
+    _videoTracks = [NSMutableArray arrayWithCapacity:videoTracks.size()];
+    _nativeMediaStream = nativeMediaStream;
+
+    for (auto &track : audioTracks) {
+      RTCMediaStreamTrackType type = RTCMediaStreamTrackTypeAudio;
+      RTCAudioTrack *audioTrack =
+          [[RTCAudioTrack alloc] initWithFactory:_factory nativeTrack:track type:type];
+      [_audioTracks addObject:audioTrack];
+    }
+
+    for (auto &track : videoTracks) {
+      RTCMediaStreamTrackType type = RTCMediaStreamTrackTypeVideo;
+      RTCVideoTrack *videoTrack =
+          [[RTCVideoTrack alloc] initWithFactory:_factory nativeTrack:track type:type];
+      [_videoTracks addObject:videoTrack];
+    }
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCMediaStreamTrack+Private.h b/sdk/objc/api/peerconnection/RTCMediaStreamTrack+Private.h
new file mode 100644
index 0000000..7f8810c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStreamTrack+Private.h
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2015 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 "RTCMediaStreamTrack.h"
+
+#include "api/mediastreaminterface.h"
+
+typedef NS_ENUM(NSInteger, RTCMediaStreamTrackType) {
+  RTCMediaStreamTrackTypeAudio,
+  RTCMediaStreamTrackTypeVideo,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+@interface RTCMediaStreamTrack ()
+
+@property(nonatomic, readonly) RTCPeerConnectionFactory *factory;
+
+/**
+ * The native MediaStreamTrackInterface passed in or created during
+ * construction.
+ */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack;
+
+/**
+ * Initialize an RTCMediaStreamTrack from a native MediaStreamTrackInterface.
+ */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
+                           type:(RTCMediaStreamTrackType)type NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack;
+
+- (BOOL)isEqualToTrack:(RTCMediaStreamTrack *)track;
+
++ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
+        (RTCMediaStreamTrackState)state;
+
++ (RTCMediaStreamTrackState)trackStateForNativeState:
+        (webrtc::MediaStreamTrackInterface::TrackState)nativeState;
+
++ (NSString *)stringForState:(RTCMediaStreamTrackState)state;
+
++ (RTCMediaStreamTrack *)mediaTrackForNativeTrack:
+                             (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
+                                          factory:(RTCPeerConnectionFactory *)factory;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaStreamTrack.h b/sdk/objc/api/peerconnection/RTCMediaStreamTrack.h
new file mode 100644
index 0000000..60c9af4
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStreamTrack.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2015 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"
+
+/**
+ * Represents the state of the track. This exposes the same states in C++.
+ */
+typedef NS_ENUM(NSInteger, RTCMediaStreamTrackState) {
+  RTCMediaStreamTrackStateLive,
+  RTCMediaStreamTrackStateEnded
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXTERN NSString *const kRTCMediaStreamTrackKindAudio;
+RTC_EXTERN NSString *const kRTCMediaStreamTrackKindVideo;
+
+RTC_EXPORT
+@interface RTCMediaStreamTrack : NSObject
+
+/**
+ * The kind of track. For example, "audio" if this track represents an audio
+ * track and "video" if this track represents a video track.
+ */
+@property(nonatomic, readonly) NSString *kind;
+
+/** An identifier string. */
+@property(nonatomic, readonly) NSString *trackId;
+
+/** The enabled state of the track. */
+@property(nonatomic, assign) BOOL isEnabled;
+
+/** The state of the track. */
+@property(nonatomic, readonly) RTCMediaStreamTrackState readyState;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMediaStreamTrack.mm b/sdk/objc/api/peerconnection/RTCMediaStreamTrack.mm
new file mode 100644
index 0000000..07992a0
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMediaStreamTrack.mm
@@ -0,0 +1,160 @@
+/*
+ *  Copyright 2015 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 "RTCAudioTrack+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCVideoTrack+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+NSString * const kRTCMediaStreamTrackKindAudio =
+    @(webrtc::MediaStreamTrackInterface::kAudioKind);
+NSString * const kRTCMediaStreamTrackKindVideo =
+    @(webrtc::MediaStreamTrackInterface::kVideoKind);
+
+@implementation RTCMediaStreamTrack {
+  RTCPeerConnectionFactory *_factory;
+  rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> _nativeTrack;
+  RTCMediaStreamTrackType _type;
+}
+
+- (NSString *)kind {
+  return [NSString stringForStdString:_nativeTrack->kind()];
+}
+
+- (NSString *)trackId {
+  return [NSString stringForStdString:_nativeTrack->id()];
+}
+
+- (BOOL)isEnabled {
+  return _nativeTrack->enabled();
+}
+
+- (void)setIsEnabled:(BOOL)isEnabled {
+  _nativeTrack->set_enabled(isEnabled);
+}
+
+- (RTCMediaStreamTrackState)readyState {
+  return [[self class] trackStateForNativeState:_nativeTrack->state()];
+}
+
+- (NSString *)description {
+  NSString *readyState = [[self class] stringForState:self.readyState];
+  return [NSString stringWithFormat:@"RTCMediaStreamTrack:\n%@\n%@\n%@\n%@",
+                                    self.kind,
+                                    self.trackId,
+                                    self.isEnabled ? @"enabled" : @"disabled",
+                                    readyState];
+}
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) {
+    return YES;
+  }
+  if (![object isMemberOfClass:[self class]]) {
+    return NO;
+  }
+  return [self isEqualToTrack:(RTCMediaStreamTrack *)object];
+}
+
+- (NSUInteger)hash {
+  return (NSUInteger)_nativeTrack.get();
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
+  return _nativeTrack;
+}
+
+@synthesize factory = _factory;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
+                           type:(RTCMediaStreamTrackType)type {
+  NSParameterAssert(nativeTrack);
+  NSParameterAssert(factory);
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeTrack = nativeTrack;
+    _type = type;
+  }
+  return self;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
+  NSParameterAssert(nativeTrack);
+  if (nativeTrack->kind() ==
+      std::string(webrtc::MediaStreamTrackInterface::kAudioKind)) {
+    return [self initWithFactory:factory nativeTrack:nativeTrack type:RTCMediaStreamTrackTypeAudio];
+  }
+  if (nativeTrack->kind() ==
+      std::string(webrtc::MediaStreamTrackInterface::kVideoKind)) {
+    return [self initWithFactory:factory nativeTrack:nativeTrack type:RTCMediaStreamTrackTypeVideo];
+  }
+  return nil;
+}
+
+- (BOOL)isEqualToTrack:(RTCMediaStreamTrack *)track {
+  if (!track) {
+    return NO;
+  }
+  return _nativeTrack == track.nativeTrack;
+}
+
++ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
+    (RTCMediaStreamTrackState)state {
+  switch (state) {
+    case RTCMediaStreamTrackStateLive:
+      return webrtc::MediaStreamTrackInterface::kLive;
+    case RTCMediaStreamTrackStateEnded:
+      return webrtc::MediaStreamTrackInterface::kEnded;
+  }
+}
+
++ (RTCMediaStreamTrackState)trackStateForNativeState:
+    (webrtc::MediaStreamTrackInterface::TrackState)nativeState {
+  switch (nativeState) {
+    case webrtc::MediaStreamTrackInterface::kLive:
+      return RTCMediaStreamTrackStateLive;
+    case webrtc::MediaStreamTrackInterface::kEnded:
+      return RTCMediaStreamTrackStateEnded;
+  }
+}
+
++ (NSString *)stringForState:(RTCMediaStreamTrackState)state {
+  switch (state) {
+    case RTCMediaStreamTrackStateLive:
+      return @"Live";
+    case RTCMediaStreamTrackStateEnded:
+      return @"Ended";
+  }
+}
+
++ (RTCMediaStreamTrack *)mediaTrackForNativeTrack:
+                             (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
+                                          factory:(RTCPeerConnectionFactory *)factory {
+  NSParameterAssert(nativeTrack);
+  NSParameterAssert(factory);
+  if (nativeTrack->kind() == webrtc::MediaStreamTrackInterface::kAudioKind) {
+    return [[RTCAudioTrack alloc] initWithFactory:factory
+                                      nativeTrack:nativeTrack
+                                             type:RTCMediaStreamTrackTypeAudio];
+  } else if (nativeTrack->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
+    return [[RTCVideoTrack alloc] initWithFactory:factory
+                                      nativeTrack:nativeTrack
+                                             type:RTCMediaStreamTrackTypeVideo];
+  } else {
+    return [[RTCMediaStreamTrack alloc] initWithFactory:factory nativeTrack:nativeTrack];
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCMetrics.h b/sdk/objc/api/peerconnection/RTCMetrics.h
new file mode 100644
index 0000000..6629fda
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMetrics.h
@@ -0,0 +1,23 @@
+/*
+ *  Copyright 2016 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"
+#import "RTCMetricsSampleInfo.h"
+
+/**
+ * Enables gathering of metrics (which can be fetched with
+ * RTCGetAndResetMetrics). Must be called before any other call into WebRTC.
+ */
+RTC_EXTERN void RTCEnableMetrics(void);
+
+/** Gets and clears native histograms. */
+RTC_EXTERN NSArray<RTCMetricsSampleInfo*>* RTCGetAndResetMetrics(void);
diff --git a/sdk/objc/api/peerconnection/RTCMetrics.mm b/sdk/objc/api/peerconnection/RTCMetrics.mm
new file mode 100644
index 0000000..8ca9d96
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMetrics.mm
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2016 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 "RTCMetrics.h"
+
+#import "RTCMetricsSampleInfo+Private.h"
+
+void RTCEnableMetrics(void) {
+  webrtc::metrics::Enable();
+}
+
+NSArray<RTCMetricsSampleInfo *> *RTCGetAndResetMetrics(void) {
+  std::map<std::string, std::unique_ptr<webrtc::metrics::SampleInfo>>
+      histograms;
+  webrtc::metrics::GetAndReset(&histograms);
+
+  NSMutableArray *metrics =
+      [NSMutableArray arrayWithCapacity:histograms.size()];
+  for (auto const &histogram : histograms) {
+    RTCMetricsSampleInfo *metric = [[RTCMetricsSampleInfo alloc]
+        initWithNativeSampleInfo:*histogram.second];
+    [metrics addObject:metric];
+  }
+  return metrics;
+}
diff --git a/sdk/objc/api/peerconnection/RTCMetricsSampleInfo+Private.h b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo+Private.h
new file mode 100644
index 0000000..03eb8e7
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2016 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 "RTCMetricsSampleInfo.h"
+
+// Adding 'nogncheck' to disable the gn include headers check.
+// We don't want to depend on 'system_wrappers:metrics_default' because
+// clients should be able to provide their own implementation.
+#include "system_wrappers/include/metrics_default.h"  // nogncheck
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCMetricsSampleInfo ()
+
+/** Initialize an RTCMetricsSampleInfo object from native SampleInfo. */
+- (instancetype)initWithNativeSampleInfo:(const webrtc::metrics::SampleInfo &)info;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.h b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.h
new file mode 100644
index 0000000..707f866
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2016 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
+
+RTC_EXPORT
+@interface RTCMetricsSampleInfo : NSObject
+
+/**
+ * Example of RTCMetricsSampleInfo:
+ * name: "WebRTC.Video.InputFramesPerSecond"
+ * min: 1
+ * max: 100
+ * bucketCount: 50
+ * samples: [29]:2 [30]:1
+ */
+
+/** The name of the histogram. */
+@property(nonatomic, readonly) NSString *name;
+
+/** The minimum bucket value. */
+@property(nonatomic, readonly) int min;
+
+/** The maximum bucket value. */
+@property(nonatomic, readonly) int max;
+
+/** The number of buckets. */
+@property(nonatomic, readonly) int bucketCount;
+
+/** A dictionary holding the samples <value, # of events>. */
+@property(nonatomic, readonly) NSDictionary<NSNumber *, NSNumber *> *samples;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.mm b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.mm
new file mode 100644
index 0000000..a4937fb
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCMetricsSampleInfo.mm
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2016 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 "RTCMetricsSampleInfo+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCMetricsSampleInfo
+
+@synthesize name = _name;
+@synthesize min = _min;
+@synthesize max = _max;
+@synthesize bucketCount = _bucketCount;
+@synthesize samples = _samples;
+
+#pragma mark - Private
+
+- (instancetype)initWithNativeSampleInfo:
+    (const webrtc::metrics::SampleInfo &)info {
+  if (self = [super init]) {
+    _name = [NSString stringForStdString:info.name];
+    _min = info.min;
+    _max = info.max;
+    _bucketCount = info.bucket_count;
+
+    NSMutableDictionary *samples =
+        [NSMutableDictionary dictionaryWithCapacity:info.samples.size()];
+    for (auto const &sample : info.samples) {
+      [samples setObject:@(sample.second) forKey:@(sample.first)];
+    }
+    _samples = samples;
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm b/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm
new file mode 100644
index 0000000..6c84fa3
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnection+Private.h"
+
+#import "RTCDataChannel+Private.h"
+#import "RTCDataChannelConfiguration+Private.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCPeerConnection (DataChannel)
+
+- (nullable RTCDataChannel *)dataChannelForLabel:(NSString *)label
+                                   configuration:(RTCDataChannelConfiguration *)configuration {
+  std::string labelString = [NSString stdStringForString:label];
+  const webrtc::DataChannelInit nativeInit =
+      configuration.nativeDataChannelInit;
+  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
+      self.nativePeerConnection->CreateDataChannel(labelString,
+                                                   &nativeInit);
+  if (!dataChannel) {
+    return nil;
+  }
+  return [[RTCDataChannel alloc] initWithFactory:self.factory nativeDataChannel:dataChannel];
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h
new file mode 100644
index 0000000..f0322a7
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h
@@ -0,0 +1,34 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCPeerConnection.h"
+
+#include <memory>
+
+namespace rtc {
+class BitrateAllocationStrategy;
+}  // namespace rtc
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * This class extension exposes methods that work directly with injectable C++ components.
+ */
+@interface RTCPeerConnection ()
+
+/** Sets current strategy. If not set default WebRTC allocator will be used. May be changed during
+ *  an active session.
+ */
+- (void)setBitrateAllocationStrategy:
+        (std::unique_ptr<rtc::BitrateAllocationStrategy>)bitrateAllocationStrategy;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h
new file mode 100644
index 0000000..b6440cd
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h
@@ -0,0 +1,106 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnection.h"
+
+#include "api/peerconnectioninterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+namespace webrtc {
+
+/**
+ * These objects are created by RTCPeerConnectionFactory to wrap an
+ * id<RTCPeerConnectionDelegate> and call methods on that interface.
+ */
+class PeerConnectionDelegateAdapter : public PeerConnectionObserver {
+ public:
+  PeerConnectionDelegateAdapter(RTCPeerConnection *peerConnection);
+  ~PeerConnectionDelegateAdapter() override;
+
+  void OnSignalingChange(PeerConnectionInterface::SignalingState new_state) override;
+
+  void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) override;
+
+  void OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) override;
+
+  void OnTrack(rtc::scoped_refptr<RtpTransceiverInterface> transceiver) override;
+
+  void OnDataChannel(rtc::scoped_refptr<DataChannelInterface> data_channel) override;
+
+  void OnRenegotiationNeeded() override;
+
+  void OnIceConnectionChange(PeerConnectionInterface::IceConnectionState new_state) override;
+
+  void OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state) override;
+
+  void OnIceCandidate(const IceCandidateInterface *candidate) override;
+
+  void OnIceCandidatesRemoved(const std::vector<cricket::Candidate> &candidates) override;
+
+  void OnAddTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver,
+                  const std::vector<rtc::scoped_refptr<MediaStreamInterface>> &streams) override;
+
+  void OnRemoveTrack(rtc::scoped_refptr<RtpReceiverInterface> receiver) override;
+
+ private:
+  __weak RTCPeerConnection *peer_connection_;
+};
+
+}  // namespace webrtc
+
+@interface RTCPeerConnection ()
+
+/** The factory used to create this RTCPeerConnection */
+@property(nonatomic, readonly) RTCPeerConnectionFactory *factory;
+
+/** The native PeerConnectionInterface created during construction. */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::PeerConnectionInterface>
+    nativePeerConnection;
+
+/** Initialize an RTCPeerConnection with a configuration, constraints, and
+ *  delegate.
+ */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                  configuration:(RTCConfiguration *)configuration
+                    constraints:(RTCMediaConstraints *)constraints
+                       delegate:(nullable id<RTCPeerConnectionDelegate>)delegate
+    NS_DESIGNATED_INITIALIZER;
+
++ (webrtc::PeerConnectionInterface::SignalingState)nativeSignalingStateForState:
+        (RTCSignalingState)state;
+
++ (RTCSignalingState)signalingStateForNativeState:
+        (webrtc::PeerConnectionInterface::SignalingState)nativeState;
+
++ (NSString *)stringForSignalingState:(RTCSignalingState)state;
+
++ (webrtc::PeerConnectionInterface::IceConnectionState)nativeIceConnectionStateForState:
+        (RTCIceConnectionState)state;
+
++ (RTCIceConnectionState)iceConnectionStateForNativeState:
+        (webrtc::PeerConnectionInterface::IceConnectionState)nativeState;
+
++ (NSString *)stringForIceConnectionState:(RTCIceConnectionState)state;
+
++ (webrtc::PeerConnectionInterface::IceGatheringState)nativeIceGatheringStateForState:
+        (RTCIceGatheringState)state;
+
++ (RTCIceGatheringState)iceGatheringStateForNativeState:
+        (webrtc::PeerConnectionInterface::IceGatheringState)nativeState;
+
++ (NSString *)stringForIceGatheringState:(RTCIceGatheringState)state;
+
++ (webrtc::PeerConnectionInterface::StatsOutputLevel)nativeStatsOutputLevelForLevel:
+        (RTCStatsOutputLevel)level;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm b/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm
new file mode 100644
index 0000000..72e8e5a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Stats.mm
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnection+Private.h"
+
+#import "RTCLegacyStatsReport+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "helpers/NSString+StdString.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+class StatsObserverAdapter : public StatsObserver {
+ public:
+  StatsObserverAdapter(void (^completionHandler)
+      (NSArray<RTCLegacyStatsReport *> *stats)) {
+    completion_handler_ = completionHandler;
+  }
+
+  ~StatsObserverAdapter() override { completion_handler_ = nil; }
+
+  void OnComplete(const StatsReports& reports) override {
+    RTC_DCHECK(completion_handler_);
+    NSMutableArray *stats = [NSMutableArray arrayWithCapacity:reports.size()];
+    for (const auto* report : reports) {
+      RTCLegacyStatsReport *statsReport =
+          [[RTCLegacyStatsReport alloc] initWithNativeReport:*report];
+      [stats addObject:statsReport];
+    }
+    completion_handler_(stats);
+    completion_handler_ = nil;
+  }
+
+ private:
+  void (^completion_handler_)(NSArray<RTCLegacyStatsReport *> *stats);
+};
+}  // namespace webrtc
+
+@implementation RTCPeerConnection (Stats)
+
+- (void)statsForTrack:(RTCMediaStreamTrack *)mediaStreamTrack
+     statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel
+    completionHandler:
+    (void (^)(NSArray<RTCLegacyStatsReport *> *stats))completionHandler {
+  rtc::scoped_refptr<webrtc::StatsObserverAdapter> observer(
+      new rtc::RefCountedObject<webrtc::StatsObserverAdapter>
+          (completionHandler));
+  webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel =
+      [[self class] nativeStatsOutputLevelForLevel:statsOutputLevel];
+  self.nativePeerConnection->GetStats(
+      observer, mediaStreamTrack.nativeTrack, nativeOutputLevel);
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.h b/sdk/objc/api/peerconnection/RTCPeerConnection.h
new file mode 100644
index 0000000..fa1e3c1
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection.h
@@ -0,0 +1,316 @@
+/*
+ *  Copyright 2015 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"
+
+@class RTCConfiguration;
+@class RTCDataChannel;
+@class RTCDataChannelConfiguration;
+@class RTCIceCandidate;
+@class RTCMediaConstraints;
+@class RTCMediaStream;
+@class RTCMediaStreamTrack;
+@class RTCPeerConnectionFactory;
+@class RTCRtpReceiver;
+@class RTCRtpSender;
+@class RTCRtpTransceiver;
+@class RTCRtpTransceiverInit;
+@class RTCSessionDescription;
+@class RTCLegacyStatsReport;
+
+typedef NS_ENUM(NSInteger, RTCRtpMediaType);
+
+NS_ASSUME_NONNULL_BEGIN
+
+extern NSString *const kRTCPeerConnectionErrorDomain;
+extern int const kRTCSessionDescriptionErrorCode;
+
+/** Represents the signaling state of the peer connection. */
+typedef NS_ENUM(NSInteger, RTCSignalingState) {
+  RTCSignalingStateStable,
+  RTCSignalingStateHaveLocalOffer,
+  RTCSignalingStateHaveLocalPrAnswer,
+  RTCSignalingStateHaveRemoteOffer,
+  RTCSignalingStateHaveRemotePrAnswer,
+  // Not an actual state, represents the total number of states.
+  RTCSignalingStateClosed,
+};
+
+/** Represents the ice connection state of the peer connection. */
+typedef NS_ENUM(NSInteger, RTCIceConnectionState) {
+  RTCIceConnectionStateNew,
+  RTCIceConnectionStateChecking,
+  RTCIceConnectionStateConnected,
+  RTCIceConnectionStateCompleted,
+  RTCIceConnectionStateFailed,
+  RTCIceConnectionStateDisconnected,
+  RTCIceConnectionStateClosed,
+  RTCIceConnectionStateCount,
+};
+
+/** Represents the ice gathering state of the peer connection. */
+typedef NS_ENUM(NSInteger, RTCIceGatheringState) {
+  RTCIceGatheringStateNew,
+  RTCIceGatheringStateGathering,
+  RTCIceGatheringStateComplete,
+};
+
+/** Represents the stats output level. */
+typedef NS_ENUM(NSInteger, RTCStatsOutputLevel) {
+  RTCStatsOutputLevelStandard,
+  RTCStatsOutputLevelDebug,
+};
+
+@class RTCPeerConnection;
+
+RTC_EXPORT
+@protocol RTCPeerConnectionDelegate <NSObject>
+
+/** Called when the SignalingState changed. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didChangeSignalingState:(RTCSignalingState)stateChanged;
+
+/** Called when media is received on a new stream from remote peer. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream;
+
+/** Called when a remote peer closes a stream.
+ *  This is not called when RTCSdpSemanticsUnifiedPlan is specified.
+ */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveStream:(RTCMediaStream *)stream;
+
+/** Called when negotiation is needed, for example ICE has restarted. */
+- (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection;
+
+/** Called any time the IceConnectionState changes. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didChangeIceConnectionState:(RTCIceConnectionState)newState;
+
+/** Called any time the IceGatheringState changes. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didChangeIceGatheringState:(RTCIceGatheringState)newState;
+
+/** New ice candidate has been found. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didGenerateIceCandidate:(RTCIceCandidate *)candidate;
+
+/** Called when a group of local Ice candidates have been removed. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates;
+
+/** New data channel has been opened. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didOpenDataChannel:(RTCDataChannel *)dataChannel;
+
+/** Called when signaling indicates a transceiver will be receiving media from
+ *  the remote endpoint.
+ *  This is only called with RTCSdpSemanticsUnifiedPlan specified.
+ */
+@optional
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didStartReceivingOnTransceiver:(RTCRtpTransceiver *)transceiver;
+
+/** Called when a receiver and its track are created. */
+@optional
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+        didAddReceiver:(RTCRtpReceiver *)rtpReceiver
+               streams:(NSArray<RTCMediaStream *> *)mediaStreams;
+
+/** Called when the receiver and its track are removed. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+     didRemoveReceiver:(RTCRtpReceiver *)rtpReceiver;
+
+@end
+
+RTC_EXPORT
+@interface RTCPeerConnection : NSObject
+
+/** The object that will be notifed about events such as state changes and
+ *  streams being added or removed.
+ */
+@property(nonatomic, weak, nullable) id<RTCPeerConnectionDelegate> delegate;
+/** This property is not available with RTCSdpSemanticsUnifiedPlan. Please use
+ *  |senders| instead.
+ */
+@property(nonatomic, readonly) NSArray<RTCMediaStream *> *localStreams;
+@property(nonatomic, readonly, nullable) RTCSessionDescription *localDescription;
+@property(nonatomic, readonly, nullable) RTCSessionDescription *remoteDescription;
+@property(nonatomic, readonly) RTCSignalingState signalingState;
+@property(nonatomic, readonly) RTCIceConnectionState iceConnectionState;
+@property(nonatomic, readonly) RTCIceGatheringState iceGatheringState;
+@property(nonatomic, readonly, copy) RTCConfiguration *configuration;
+
+/** Gets all RTCRtpSenders associated with this peer connection.
+ *  Note: reading this property returns different instances of RTCRtpSender.
+ *  Use isEqual: instead of == to compare RTCRtpSender instances.
+ */
+@property(nonatomic, readonly) NSArray<RTCRtpSender *> *senders;
+
+/** Gets all RTCRtpReceivers associated with this peer connection.
+ *  Note: reading this property returns different instances of RTCRtpReceiver.
+ *  Use isEqual: instead of == to compare RTCRtpReceiver instances.
+ */
+@property(nonatomic, readonly) NSArray<RTCRtpReceiver *> *receivers;
+
+/** Gets all RTCRtpTransceivers associated with this peer connection.
+ *  Note: reading this property returns different instances of
+ *  RTCRtpTransceiver. Use isEqual: instead of == to compare RTCRtpTransceiver
+ *  instances.
+ *  This is only available with RTCSdpSemanticsUnifiedPlan specified.
+ */
+@property(nonatomic, readonly) NSArray<RTCRtpTransceiver *> *transceivers;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Sets the PeerConnection's global configuration to |configuration|.
+ *  Any changes to STUN/TURN servers or ICE candidate policy will affect the
+ *  next gathering phase, and cause the next call to createOffer to generate
+ *  new ICE credentials. Note that the BUNDLE and RTCP-multiplexing policies
+ *  cannot be changed with this method.
+ */
+- (BOOL)setConfiguration:(RTCConfiguration *)configuration;
+
+/** Terminate all media and close the transport. */
+- (void)close;
+
+/** Provide a remote candidate to the ICE Agent. */
+- (void)addIceCandidate:(RTCIceCandidate *)candidate;
+
+/** Remove a group of remote candidates from the ICE Agent. */
+- (void)removeIceCandidates:(NSArray<RTCIceCandidate *> *)candidates;
+
+/** Add a new media stream to be sent on this peer connection.
+ *  This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use
+ *  addTrack instead.
+ */
+- (void)addStream:(RTCMediaStream *)stream;
+
+/** Remove the given media stream from this peer connection.
+ *  This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use
+ *  removeTrack instead.
+ */
+- (void)removeStream:(RTCMediaStream *)stream;
+
+/** Add a new media stream track to be sent on this peer connection, and return
+ *  the newly created RTCRtpSender. The RTCRtpSender will be associated with
+ *  the streams specified in the |streamIds| list.
+ *
+ *  Errors: If an error occurs, returns nil. An error can occur if:
+ *  - A sender already exists for the track.
+ *  - The peer connection is closed.
+ */
+- (RTCRtpSender *)addTrack:(RTCMediaStreamTrack *)track streamIds:(NSArray<NSString *> *)streamIds;
+
+/** With PlanB semantics, removes an RTCRtpSender from this peer connection.
+ *
+ *  With UnifiedPlan semantics, sets sender's track to null and removes the
+ *  send component from the associated RTCRtpTransceiver's direction.
+ *
+ *  Returns YES on success.
+ */
+- (BOOL)removeTrack:(RTCRtpSender *)sender;
+
+/** addTransceiver creates a new RTCRtpTransceiver and adds it to the set of
+ *  transceivers. Adding a transceiver will cause future calls to CreateOffer
+ *  to add a media description for the corresponding transceiver.
+ *
+ *  The initial value of |mid| in the returned transceiver is nil. Setting a
+ *  new session description may change it to a non-nil value.
+ *
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
+ *
+ *  Optionally, an RtpTransceiverInit structure can be specified to configure
+ *  the transceiver from construction. If not specified, the transceiver will
+ *  default to having a direction of kSendRecv and not be part of any streams.
+ *
+ *  These methods are only available when Unified Plan is enabled (see
+ *  RTCConfiguration).
+ */
+
+/** Adds a transceiver with a sender set to transmit the given track. The kind
+ *  of the transceiver (and sender/receiver) will be derived from the kind of
+ *  the track.
+ */
+- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track;
+- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track
+                                          init:(RTCRtpTransceiverInit *)init;
+
+/** Adds a transceiver with the given kind. Can either be RTCRtpMediaTypeAudio
+ *  or RTCRtpMediaTypeVideo.
+ */
+- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType;
+- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType
+                                       init:(RTCRtpTransceiverInit *)init;
+
+/** Generate an SDP offer. */
+- (void)offerForConstraints:(RTCMediaConstraints *)constraints
+          completionHandler:(nullable void (^)(RTCSessionDescription *_Nullable sdp,
+                                               NSError *_Nullable error))completionHandler;
+
+/** Generate an SDP answer. */
+- (void)answerForConstraints:(RTCMediaConstraints *)constraints
+           completionHandler:(nullable void (^)(RTCSessionDescription *_Nullable sdp,
+                                                NSError *_Nullable error))completionHandler;
+
+/** Apply the supplied RTCSessionDescription as the local description. */
+- (void)setLocalDescription:(RTCSessionDescription *)sdp
+          completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler;
+
+/** Apply the supplied RTCSessionDescription as the remote description. */
+- (void)setRemoteDescription:(RTCSessionDescription *)sdp
+           completionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler;
+
+/** Limits the bandwidth allocated for all RTP streams sent by this
+ *  PeerConnection. Nil parameters will be unchanged. Setting
+ * |currentBitrateBps| will force the available bitrate estimate to the given
+ *  value. Returns YES if the parameters were successfully updated.
+ */
+- (BOOL)setBweMinBitrateBps:(nullable NSNumber *)minBitrateBps
+          currentBitrateBps:(nullable NSNumber *)currentBitrateBps
+              maxBitrateBps:(nullable NSNumber *)maxBitrateBps;
+
+/** Start or stop recording an Rtc EventLog. */
+- (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath maxSizeInBytes:(int64_t)maxSizeInBytes;
+- (void)stopRtcEventLog;
+
+@end
+
+@interface RTCPeerConnection (Media)
+
+/** Create an RTCRtpSender with the specified kind and media stream ID.
+ *  See RTCMediaStreamTrack.h for available kinds.
+ *  This method is not supported with RTCSdpSemanticsUnifiedPlan. Please use
+ *  addTransceiver instead.
+ */
+- (RTCRtpSender *)senderWithKind:(NSString *)kind streamId:(NSString *)streamId;
+
+@end
+
+@interface RTCPeerConnection (DataChannel)
+
+/** Create a new data channel with the given label and configuration. */
+- (nullable RTCDataChannel *)dataChannelForLabel:(NSString *)label
+                                   configuration:(RTCDataChannelConfiguration *)configuration;
+
+@end
+
+@interface RTCPeerConnection (Stats)
+
+/** Gather stats for the given RTCMediaStreamTrack. If |mediaStreamTrack| is nil
+ *  statistics are gathered for all tracks.
+ */
+- (void)statsForTrack:(nullable RTCMediaStreamTrack *)mediaStreamTrack
+     statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel
+    completionHandler:(nullable void (^)(NSArray<RTCLegacyStatsReport *> *stats))completionHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/sdk/objc/api/peerconnection/RTCPeerConnection.mm
new file mode 100644
index 0000000..5277489
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection.mm
@@ -0,0 +1,748 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnection+Private.h"
+
+#import "RTCConfiguration+Private.h"
+#import "RTCDataChannel+Private.h"
+#import "RTCIceCandidate+Private.h"
+#import "RTCLegacyStatsReport+Private.h"
+#import "RTCMediaConstraints+Private.h"
+#import "RTCMediaStream+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCPeerConnection+Native.h"
+#import "RTCPeerConnectionFactory+Private.h"
+#import "RTCRtpReceiver+Private.h"
+#import "RTCRtpSender+Private.h"
+#import "RTCRtpTransceiver+Private.h"
+#import "RTCSessionDescription+Private.h"
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include <memory>
+
+#include "api/jsepicecandidate.h"
+#include "rtc_base/checks.h"
+
+NSString * const kRTCPeerConnectionErrorDomain =
+    @"org.webrtc.RTCPeerConnection";
+int const kRTCPeerConnnectionSessionDescriptionError = -1;
+
+namespace webrtc {
+
+class CreateSessionDescriptionObserverAdapter
+    : public CreateSessionDescriptionObserver {
+ public:
+  CreateSessionDescriptionObserverAdapter(
+      void (^completionHandler)(RTCSessionDescription *sessionDescription,
+                                NSError *error)) {
+    completion_handler_ = completionHandler;
+  }
+
+  ~CreateSessionDescriptionObserverAdapter() override { completion_handler_ = nil; }
+
+  void OnSuccess(SessionDescriptionInterface *desc) override {
+    RTC_DCHECK(completion_handler_);
+    std::unique_ptr<webrtc::SessionDescriptionInterface> description =
+        std::unique_ptr<webrtc::SessionDescriptionInterface>(desc);
+    RTCSessionDescription* session =
+        [[RTCSessionDescription alloc] initWithNativeDescription:
+            description.get()];
+    completion_handler_(session, nil);
+    completion_handler_ = nil;
+  }
+
+  void OnFailure(RTCError error) override {
+    RTC_DCHECK(completion_handler_);
+    // TODO(hta): Add handling of error.type()
+    NSString *str = [NSString stringForStdString:error.message()];
+    NSError* err =
+        [NSError errorWithDomain:kRTCPeerConnectionErrorDomain
+                            code:kRTCPeerConnnectionSessionDescriptionError
+                        userInfo:@{ NSLocalizedDescriptionKey : str }];
+    completion_handler_(nil, err);
+    completion_handler_ = nil;
+  }
+
+ private:
+  void (^completion_handler_)
+      (RTCSessionDescription *sessionDescription, NSError *error);
+};
+
+class SetSessionDescriptionObserverAdapter :
+    public SetSessionDescriptionObserver {
+ public:
+  SetSessionDescriptionObserverAdapter(void (^completionHandler)
+      (NSError *error)) {
+    completion_handler_ = completionHandler;
+  }
+
+  ~SetSessionDescriptionObserverAdapter() override { completion_handler_ = nil; }
+
+  void OnSuccess() override {
+    RTC_DCHECK(completion_handler_);
+    completion_handler_(nil);
+    completion_handler_ = nil;
+  }
+
+  void OnFailure(RTCError error) override {
+    RTC_DCHECK(completion_handler_);
+    // TODO(hta): Add handling of error.type()
+    NSString *str = [NSString stringForStdString:error.message()];
+    NSError* err =
+        [NSError errorWithDomain:kRTCPeerConnectionErrorDomain
+                            code:kRTCPeerConnnectionSessionDescriptionError
+                        userInfo:@{ NSLocalizedDescriptionKey : str }];
+    completion_handler_(err);
+    completion_handler_ = nil;
+  }
+
+ private:
+  void (^completion_handler_)(NSError *error);
+};
+
+PeerConnectionDelegateAdapter::PeerConnectionDelegateAdapter(
+    RTCPeerConnection *peerConnection) {
+  peer_connection_ = peerConnection;
+}
+
+PeerConnectionDelegateAdapter::~PeerConnectionDelegateAdapter() {
+  peer_connection_ = nil;
+}
+
+void PeerConnectionDelegateAdapter::OnSignalingChange(
+    PeerConnectionInterface::SignalingState new_state) {
+  RTCSignalingState state =
+      [[RTCPeerConnection class] signalingStateForNativeState:new_state];
+  RTCPeerConnection *peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnection:peer_connection
+                   didChangeSignalingState:state];
+}
+
+void PeerConnectionDelegateAdapter::OnAddStream(
+    rtc::scoped_refptr<MediaStreamInterface> stream) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  RTCMediaStream *mediaStream =
+      [[RTCMediaStream alloc] initWithFactory:peer_connection.factory nativeMediaStream:stream];
+  [peer_connection.delegate peerConnection:peer_connection
+                              didAddStream:mediaStream];
+}
+
+void PeerConnectionDelegateAdapter::OnRemoveStream(
+    rtc::scoped_refptr<MediaStreamInterface> stream) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  RTCMediaStream *mediaStream =
+      [[RTCMediaStream alloc] initWithFactory:peer_connection.factory nativeMediaStream:stream];
+
+  [peer_connection.delegate peerConnection:peer_connection
+                           didRemoveStream:mediaStream];
+}
+
+void PeerConnectionDelegateAdapter::OnTrack(
+    rtc::scoped_refptr<RtpTransceiverInterface> nativeTransceiver) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  RTCRtpTransceiver *transceiver =
+      [[RTCRtpTransceiver alloc] initWithFactory:peer_connection.factory
+                            nativeRtpTransceiver:nativeTransceiver];
+  if ([peer_connection.delegate
+          respondsToSelector:@selector(peerConnection:didStartReceivingOnTransceiver:)]) {
+    [peer_connection.delegate peerConnection:peer_connection
+              didStartReceivingOnTransceiver:transceiver];
+  }
+}
+
+void PeerConnectionDelegateAdapter::OnDataChannel(
+    rtc::scoped_refptr<DataChannelInterface> data_channel) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  RTCDataChannel *dataChannel = [[RTCDataChannel alloc] initWithFactory:peer_connection.factory
+                                                      nativeDataChannel:data_channel];
+  [peer_connection.delegate peerConnection:peer_connection
+                        didOpenDataChannel:dataChannel];
+}
+
+void PeerConnectionDelegateAdapter::OnRenegotiationNeeded() {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnectionShouldNegotiate:peer_connection];
+}
+
+void PeerConnectionDelegateAdapter::OnIceConnectionChange(
+    PeerConnectionInterface::IceConnectionState new_state) {
+  RTCIceConnectionState state =
+      [[RTCPeerConnection class] iceConnectionStateForNativeState:new_state];
+  RTCPeerConnection *peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnection:peer_connection
+               didChangeIceConnectionState:state];
+}
+
+void PeerConnectionDelegateAdapter::OnIceGatheringChange(
+    PeerConnectionInterface::IceGatheringState new_state) {
+  RTCIceGatheringState state =
+      [[RTCPeerConnection class] iceGatheringStateForNativeState:new_state];
+  RTCPeerConnection *peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnection:peer_connection
+                didChangeIceGatheringState:state];
+}
+
+void PeerConnectionDelegateAdapter::OnIceCandidate(
+    const IceCandidateInterface *candidate) {
+  RTCIceCandidate *iceCandidate =
+      [[RTCIceCandidate alloc] initWithNativeCandidate:candidate];
+  RTCPeerConnection *peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnection:peer_connection
+                   didGenerateIceCandidate:iceCandidate];
+}
+
+void PeerConnectionDelegateAdapter::OnIceCandidatesRemoved(
+    const std::vector<cricket::Candidate>& candidates) {
+  NSMutableArray* ice_candidates =
+      [NSMutableArray arrayWithCapacity:candidates.size()];
+  for (const auto& candidate : candidates) {
+    std::unique_ptr<JsepIceCandidate> candidate_wrapper(
+        new JsepIceCandidate(candidate.transport_name(), -1, candidate));
+    RTCIceCandidate* ice_candidate = [[RTCIceCandidate alloc]
+        initWithNativeCandidate:candidate_wrapper.get()];
+    [ice_candidates addObject:ice_candidate];
+  }
+  RTCPeerConnection* peer_connection = peer_connection_;
+  [peer_connection.delegate peerConnection:peer_connection
+                    didRemoveIceCandidates:ice_candidates];
+}
+
+void PeerConnectionDelegateAdapter::OnAddTrack(
+    rtc::scoped_refptr<RtpReceiverInterface> receiver,
+    const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  if ([peer_connection.delegate
+          respondsToSelector:@selector(peerConnection:didAddReceiver:streams:)]) {
+    NSMutableArray *mediaStreams = [NSMutableArray arrayWithCapacity:streams.size()];
+    for (const auto& nativeStream : streams) {
+      RTCMediaStream *mediaStream = [[RTCMediaStream alloc] initWithFactory:peer_connection.factory
+                                                          nativeMediaStream:nativeStream];
+      [mediaStreams addObject:mediaStream];
+    }
+    RTCRtpReceiver *rtpReceiver =
+        [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver];
+
+    [peer_connection.delegate peerConnection:peer_connection
+                              didAddReceiver:rtpReceiver
+                                     streams:mediaStreams];
+  }
+}
+
+void PeerConnectionDelegateAdapter::OnRemoveTrack(
+    rtc::scoped_refptr<RtpReceiverInterface> receiver) {
+  RTCPeerConnection *peer_connection = peer_connection_;
+  if ([peer_connection.delegate respondsToSelector:@selector(peerConnection:didRemoveReceiver:)]) {
+    RTCRtpReceiver *rtpReceiver =
+        [[RTCRtpReceiver alloc] initWithFactory:peer_connection.factory nativeRtpReceiver:receiver];
+    [peer_connection.delegate peerConnection:peer_connection didRemoveReceiver:rtpReceiver];
+  }
+}
+
+}  // namespace webrtc
+
+
+@implementation RTCPeerConnection {
+  RTCPeerConnectionFactory *_factory;
+  NSMutableArray<RTCMediaStream *> *_localStreams;
+  std::unique_ptr<webrtc::PeerConnectionDelegateAdapter> _observer;
+  rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
+  std::unique_ptr<webrtc::MediaConstraints> _nativeConstraints;
+  BOOL _hasStartedRtcEventLog;
+}
+
+@synthesize delegate = _delegate;
+@synthesize factory = _factory;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                  configuration:(RTCConfiguration *)configuration
+                    constraints:(RTCMediaConstraints *)constraints
+                       delegate:(id<RTCPeerConnectionDelegate>)delegate {
+  NSParameterAssert(factory);
+  std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> config(
+      [configuration createNativeConfiguration]);
+  if (!config) {
+    return nil;
+  }
+  if (self = [super init]) {
+    _observer.reset(new webrtc::PeerConnectionDelegateAdapter(self));
+    _nativeConstraints = constraints.nativeConstraints;
+    CopyConstraintsIntoRtcConfiguration(_nativeConstraints.get(),
+                                        config.get());
+    _peerConnection =
+        factory.nativeFactory->CreatePeerConnection(*config,
+                                                    nullptr,
+                                                    nullptr,
+                                                    _observer.get());
+    if (!_peerConnection) {
+      return nil;
+    }
+    _factory = factory;
+    _localStreams = [[NSMutableArray alloc] init];
+    _delegate = delegate;
+  }
+  return self;
+}
+
+- (NSArray<RTCMediaStream *> *)localStreams {
+  return [_localStreams copy];
+}
+
+- (RTCSessionDescription *)localDescription {
+  const webrtc::SessionDescriptionInterface *description =
+      _peerConnection->local_description();
+  return description ?
+      [[RTCSessionDescription alloc] initWithNativeDescription:description]
+          : nil;
+}
+
+- (RTCSessionDescription *)remoteDescription {
+  const webrtc::SessionDescriptionInterface *description =
+      _peerConnection->remote_description();
+  return description ?
+      [[RTCSessionDescription alloc] initWithNativeDescription:description]
+          : nil;
+}
+
+- (RTCSignalingState)signalingState {
+  return [[self class]
+      signalingStateForNativeState:_peerConnection->signaling_state()];
+}
+
+- (RTCIceConnectionState)iceConnectionState {
+  return [[self class] iceConnectionStateForNativeState:
+      _peerConnection->ice_connection_state()];
+}
+
+- (RTCIceGatheringState)iceGatheringState {
+  return [[self class] iceGatheringStateForNativeState:
+      _peerConnection->ice_gathering_state()];
+}
+
+- (BOOL)setConfiguration:(RTCConfiguration *)configuration {
+  std::unique_ptr<webrtc::PeerConnectionInterface::RTCConfiguration> config(
+      [configuration createNativeConfiguration]);
+  if (!config) {
+    return NO;
+  }
+  CopyConstraintsIntoRtcConfiguration(_nativeConstraints.get(),
+                                      config.get());
+  return _peerConnection->SetConfiguration(*config);
+}
+
+- (RTCConfiguration *)configuration {
+  webrtc::PeerConnectionInterface::RTCConfiguration config =
+    _peerConnection->GetConfiguration();
+  return [[RTCConfiguration alloc] initWithNativeConfiguration:config];
+}
+
+- (void)close {
+  _peerConnection->Close();
+}
+
+- (void)addIceCandidate:(RTCIceCandidate *)candidate {
+  std::unique_ptr<const webrtc::IceCandidateInterface> iceCandidate(
+      candidate.nativeCandidate);
+  _peerConnection->AddIceCandidate(iceCandidate.get());
+}
+
+- (void)removeIceCandidates:(NSArray<RTCIceCandidate *> *)iceCandidates {
+  std::vector<cricket::Candidate> candidates;
+  for (RTCIceCandidate *iceCandidate in iceCandidates) {
+    std::unique_ptr<const webrtc::IceCandidateInterface> candidate(
+        iceCandidate.nativeCandidate);
+    if (candidate) {
+      candidates.push_back(candidate->candidate());
+      // Need to fill the transport name from the sdp_mid.
+      candidates.back().set_transport_name(candidate->sdp_mid());
+    }
+  }
+  if (!candidates.empty()) {
+    _peerConnection->RemoveIceCandidates(candidates);
+  }
+}
+
+- (void)addStream:(RTCMediaStream *)stream {
+  if (!_peerConnection->AddStream(stream.nativeMediaStream)) {
+    RTCLogError(@"Failed to add stream: %@", stream);
+    return;
+  }
+  [_localStreams addObject:stream];
+}
+
+- (void)removeStream:(RTCMediaStream *)stream {
+  _peerConnection->RemoveStream(stream.nativeMediaStream);
+  [_localStreams removeObject:stream];
+}
+
+- (RTCRtpSender *)addTrack:(RTCMediaStreamTrack *)track streamIds:(NSArray<NSString *> *)streamIds {
+  std::vector<std::string> nativeStreamIds;
+  for (NSString *streamId in streamIds) {
+    nativeStreamIds.push_back([streamId UTF8String]);
+  }
+  webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpSenderInterface>> nativeSenderOrError =
+      _peerConnection->AddTrack(track.nativeTrack, nativeStreamIds);
+  if (!nativeSenderOrError.ok()) {
+    RTCLogError(@"Failed to add track %@: %s", track, nativeSenderOrError.error().message());
+    return nil;
+  }
+  return [[RTCRtpSender alloc] initWithFactory:self.factory
+                               nativeRtpSender:nativeSenderOrError.MoveValue()];
+}
+
+- (BOOL)removeTrack:(RTCRtpSender *)sender {
+  bool result = _peerConnection->RemoveTrack(sender.nativeRtpSender);
+  if (!result) {
+    RTCLogError(@"Failed to remote track %@", sender);
+  }
+  return result;
+}
+
+- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track {
+  return [self addTransceiverWithTrack:track init:[[RTCRtpTransceiverInit alloc] init]];
+}
+
+- (RTCRtpTransceiver *)addTransceiverWithTrack:(RTCMediaStreamTrack *)track
+                                          init:(RTCRtpTransceiverInit *)init {
+  webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> nativeTransceiverOrError =
+      _peerConnection->AddTransceiver(track.nativeTrack, init.nativeInit);
+  if (!nativeTransceiverOrError.ok()) {
+    RTCLogError(
+        @"Failed to add transceiver %@: %s", track, nativeTransceiverOrError.error().message());
+    return nil;
+  }
+  return [[RTCRtpTransceiver alloc] initWithFactory:self.factory
+                               nativeRtpTransceiver:nativeTransceiverOrError.MoveValue()];
+}
+
+- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType {
+  return [self addTransceiverOfType:mediaType init:[[RTCRtpTransceiverInit alloc] init]];
+}
+
+- (RTCRtpTransceiver *)addTransceiverOfType:(RTCRtpMediaType)mediaType
+                                       init:(RTCRtpTransceiverInit *)init {
+  webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> nativeTransceiverOrError =
+      _peerConnection->AddTransceiver([RTCRtpReceiver nativeMediaTypeForMediaType:mediaType],
+                                      init.nativeInit);
+  if (!nativeTransceiverOrError.ok()) {
+    RTCLogError(@"Failed to add transceiver %@: %s",
+                [RTCRtpReceiver stringForMediaType:mediaType],
+                nativeTransceiverOrError.error().message());
+    return nil;
+  }
+  return [[RTCRtpTransceiver alloc] initWithFactory:self.factory
+                               nativeRtpTransceiver:nativeTransceiverOrError.MoveValue()];
+}
+
+- (void)offerForConstraints:(RTCMediaConstraints *)constraints
+          completionHandler:
+    (void (^)(RTCSessionDescription *sessionDescription,
+              NSError *error))completionHandler {
+  rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserverAdapter>
+      observer(new rtc::RefCountedObject
+          <webrtc::CreateSessionDescriptionObserverAdapter>(completionHandler));
+  webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
+  CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options);
+
+  _peerConnection->CreateOffer(observer, options);
+}
+
+- (void)answerForConstraints:(RTCMediaConstraints *)constraints
+           completionHandler:
+    (void (^)(RTCSessionDescription *sessionDescription,
+              NSError *error))completionHandler {
+  rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserverAdapter>
+      observer(new rtc::RefCountedObject
+          <webrtc::CreateSessionDescriptionObserverAdapter>(completionHandler));
+  webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
+  CopyConstraintsIntoOfferAnswerOptions(constraints.nativeConstraints.get(), &options);
+
+  _peerConnection->CreateAnswer(observer, options);
+}
+
+- (void)setLocalDescription:(RTCSessionDescription *)sdp
+          completionHandler:(void (^)(NSError *error))completionHandler {
+  rtc::scoped_refptr<webrtc::SetSessionDescriptionObserverAdapter> observer(
+      new rtc::RefCountedObject<webrtc::SetSessionDescriptionObserverAdapter>(
+          completionHandler));
+  _peerConnection->SetLocalDescription(observer, sdp.nativeDescription);
+}
+
+- (void)setRemoteDescription:(RTCSessionDescription *)sdp
+           completionHandler:(void (^)(NSError *error))completionHandler {
+  rtc::scoped_refptr<webrtc::SetSessionDescriptionObserverAdapter> observer(
+      new rtc::RefCountedObject<webrtc::SetSessionDescriptionObserverAdapter>(
+          completionHandler));
+  _peerConnection->SetRemoteDescription(observer, sdp.nativeDescription);
+}
+
+- (BOOL)setBweMinBitrateBps:(nullable NSNumber *)minBitrateBps
+          currentBitrateBps:(nullable NSNumber *)currentBitrateBps
+              maxBitrateBps:(nullable NSNumber *)maxBitrateBps {
+  webrtc::PeerConnectionInterface::BitrateParameters params;
+  if (minBitrateBps != nil) {
+    params.min_bitrate_bps = absl::optional<int>(minBitrateBps.intValue);
+  }
+  if (currentBitrateBps != nil) {
+    params.current_bitrate_bps = absl::optional<int>(currentBitrateBps.intValue);
+  }
+  if (maxBitrateBps != nil) {
+    params.max_bitrate_bps = absl::optional<int>(maxBitrateBps.intValue);
+  }
+  return _peerConnection->SetBitrate(params).ok();
+}
+
+- (void)setBitrateAllocationStrategy:
+        (std::unique_ptr<rtc::BitrateAllocationStrategy>)bitrateAllocationStrategy {
+  _peerConnection->SetBitrateAllocationStrategy(std::move(bitrateAllocationStrategy));
+}
+
+- (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath
+                      maxSizeInBytes:(int64_t)maxSizeInBytes {
+  RTC_DCHECK(filePath.length);
+  RTC_DCHECK_GT(maxSizeInBytes, 0);
+  RTC_DCHECK(!_hasStartedRtcEventLog);
+  if (_hasStartedRtcEventLog) {
+    RTCLogError(@"Event logging already started.");
+    return NO;
+  }
+  int fd = open(filePath.UTF8String, O_WRONLY | O_CREAT | O_TRUNC,
+                S_IRUSR | S_IWUSR);
+  if (fd < 0) {
+    RTCLogError(@"Error opening file: %@. Error: %d", filePath, errno);
+    return NO;
+  }
+  _hasStartedRtcEventLog =
+      _peerConnection->StartRtcEventLog(fd, maxSizeInBytes);
+  return _hasStartedRtcEventLog;
+}
+
+- (void)stopRtcEventLog {
+  _peerConnection->StopRtcEventLog();
+  _hasStartedRtcEventLog = NO;
+}
+
+- (RTCRtpSender *)senderWithKind:(NSString *)kind
+                        streamId:(NSString *)streamId {
+  std::string nativeKind = [NSString stdStringForString:kind];
+  std::string nativeStreamId = [NSString stdStringForString:streamId];
+  rtc::scoped_refptr<webrtc::RtpSenderInterface> nativeSender(
+      _peerConnection->CreateSender(nativeKind, nativeStreamId));
+  return nativeSender ?
+      [[RTCRtpSender alloc] initWithFactory:self.factory nativeRtpSender:nativeSender] :
+      nil;
+}
+
+- (NSArray<RTCRtpSender *> *)senders {
+  std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> nativeSenders(
+      _peerConnection->GetSenders());
+  NSMutableArray *senders = [[NSMutableArray alloc] init];
+  for (const auto &nativeSender : nativeSenders) {
+    RTCRtpSender *sender =
+        [[RTCRtpSender alloc] initWithFactory:self.factory nativeRtpSender:nativeSender];
+    [senders addObject:sender];
+  }
+  return senders;
+}
+
+- (NSArray<RTCRtpReceiver *> *)receivers {
+  std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> nativeReceivers(
+      _peerConnection->GetReceivers());
+  NSMutableArray *receivers = [[NSMutableArray alloc] init];
+  for (const auto &nativeReceiver : nativeReceivers) {
+    RTCRtpReceiver *receiver =
+        [[RTCRtpReceiver alloc] initWithFactory:self.factory nativeRtpReceiver:nativeReceiver];
+    [receivers addObject:receiver];
+  }
+  return receivers;
+}
+
+- (NSArray<RTCRtpTransceiver *> *)transceivers {
+  std::vector<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>> nativeTransceivers(
+      _peerConnection->GetTransceivers());
+  NSMutableArray *transceivers = [[NSMutableArray alloc] init];
+  for (auto nativeTransceiver : nativeTransceivers) {
+    RTCRtpTransceiver *transceiver = [[RTCRtpTransceiver alloc] initWithFactory:self.factory
+                                                           nativeRtpTransceiver:nativeTransceiver];
+    [transceivers addObject:transceiver];
+  }
+  return transceivers;
+}
+
+#pragma mark - Private
+
++ (webrtc::PeerConnectionInterface::SignalingState)nativeSignalingStateForState:
+    (RTCSignalingState)state {
+  switch (state) {
+    case RTCSignalingStateStable:
+      return webrtc::PeerConnectionInterface::kStable;
+    case RTCSignalingStateHaveLocalOffer:
+      return webrtc::PeerConnectionInterface::kHaveLocalOffer;
+    case RTCSignalingStateHaveLocalPrAnswer:
+      return webrtc::PeerConnectionInterface::kHaveLocalPrAnswer;
+    case RTCSignalingStateHaveRemoteOffer:
+      return webrtc::PeerConnectionInterface::kHaveRemoteOffer;
+    case RTCSignalingStateHaveRemotePrAnswer:
+      return webrtc::PeerConnectionInterface::kHaveRemotePrAnswer;
+    case RTCSignalingStateClosed:
+      return webrtc::PeerConnectionInterface::kClosed;
+  }
+}
+
++ (RTCSignalingState)signalingStateForNativeState:
+    (webrtc::PeerConnectionInterface::SignalingState)nativeState {
+  switch (nativeState) {
+    case webrtc::PeerConnectionInterface::kStable:
+      return RTCSignalingStateStable;
+    case webrtc::PeerConnectionInterface::kHaveLocalOffer:
+      return RTCSignalingStateHaveLocalOffer;
+    case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer:
+      return RTCSignalingStateHaveLocalPrAnswer;
+    case webrtc::PeerConnectionInterface::kHaveRemoteOffer:
+      return RTCSignalingStateHaveRemoteOffer;
+    case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer:
+      return RTCSignalingStateHaveRemotePrAnswer;
+    case webrtc::PeerConnectionInterface::kClosed:
+      return RTCSignalingStateClosed;
+  }
+}
+
++ (NSString *)stringForSignalingState:(RTCSignalingState)state {
+  switch (state) {
+    case RTCSignalingStateStable:
+      return @"STABLE";
+    case RTCSignalingStateHaveLocalOffer:
+      return @"HAVE_LOCAL_OFFER";
+    case RTCSignalingStateHaveLocalPrAnswer:
+      return @"HAVE_LOCAL_PRANSWER";
+    case RTCSignalingStateHaveRemoteOffer:
+      return @"HAVE_REMOTE_OFFER";
+    case RTCSignalingStateHaveRemotePrAnswer:
+      return @"HAVE_REMOTE_PRANSWER";
+    case RTCSignalingStateClosed:
+      return @"CLOSED";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::IceConnectionState)
+    nativeIceConnectionStateForState:(RTCIceConnectionState)state {
+  switch (state) {
+    case RTCIceConnectionStateNew:
+      return webrtc::PeerConnectionInterface::kIceConnectionNew;
+    case RTCIceConnectionStateChecking:
+      return webrtc::PeerConnectionInterface::kIceConnectionChecking;
+    case RTCIceConnectionStateConnected:
+      return webrtc::PeerConnectionInterface::kIceConnectionConnected;
+    case RTCIceConnectionStateCompleted:
+      return webrtc::PeerConnectionInterface::kIceConnectionCompleted;
+    case RTCIceConnectionStateFailed:
+      return webrtc::PeerConnectionInterface::kIceConnectionFailed;
+    case RTCIceConnectionStateDisconnected:
+      return webrtc::PeerConnectionInterface::kIceConnectionDisconnected;
+    case RTCIceConnectionStateClosed:
+      return webrtc::PeerConnectionInterface::kIceConnectionClosed;
+    case RTCIceConnectionStateCount:
+      return webrtc::PeerConnectionInterface::kIceConnectionMax;
+  }
+}
+
++ (RTCIceConnectionState)iceConnectionStateForNativeState:
+    (webrtc::PeerConnectionInterface::IceConnectionState)nativeState {
+  switch (nativeState) {
+    case webrtc::PeerConnectionInterface::kIceConnectionNew:
+      return RTCIceConnectionStateNew;
+    case webrtc::PeerConnectionInterface::kIceConnectionChecking:
+      return RTCIceConnectionStateChecking;
+    case webrtc::PeerConnectionInterface::kIceConnectionConnected:
+      return RTCIceConnectionStateConnected;
+    case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
+      return RTCIceConnectionStateCompleted;
+    case webrtc::PeerConnectionInterface::kIceConnectionFailed:
+      return RTCIceConnectionStateFailed;
+    case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
+      return RTCIceConnectionStateDisconnected;
+    case webrtc::PeerConnectionInterface::kIceConnectionClosed:
+      return RTCIceConnectionStateClosed;
+    case webrtc::PeerConnectionInterface::kIceConnectionMax:
+      return RTCIceConnectionStateCount;
+  }
+}
+
++ (NSString *)stringForIceConnectionState:(RTCIceConnectionState)state {
+  switch (state) {
+    case RTCIceConnectionStateNew:
+      return @"NEW";
+    case RTCIceConnectionStateChecking:
+      return @"CHECKING";
+    case RTCIceConnectionStateConnected:
+      return @"CONNECTED";
+    case RTCIceConnectionStateCompleted:
+      return @"COMPLETED";
+    case RTCIceConnectionStateFailed:
+      return @"FAILED";
+    case RTCIceConnectionStateDisconnected:
+      return @"DISCONNECTED";
+    case RTCIceConnectionStateClosed:
+      return @"CLOSED";
+    case RTCIceConnectionStateCount:
+      return @"COUNT";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::IceGatheringState)
+    nativeIceGatheringStateForState:(RTCIceGatheringState)state {
+  switch (state) {
+    case RTCIceGatheringStateNew:
+      return webrtc::PeerConnectionInterface::kIceGatheringNew;
+    case RTCIceGatheringStateGathering:
+      return webrtc::PeerConnectionInterface::kIceGatheringGathering;
+    case RTCIceGatheringStateComplete:
+      return webrtc::PeerConnectionInterface::kIceGatheringComplete;
+  }
+}
+
++ (RTCIceGatheringState)iceGatheringStateForNativeState:
+    (webrtc::PeerConnectionInterface::IceGatheringState)nativeState {
+  switch (nativeState) {
+    case webrtc::PeerConnectionInterface::kIceGatheringNew:
+      return RTCIceGatheringStateNew;
+    case webrtc::PeerConnectionInterface::kIceGatheringGathering:
+      return RTCIceGatheringStateGathering;
+    case webrtc::PeerConnectionInterface::kIceGatheringComplete:
+      return RTCIceGatheringStateComplete;
+  }
+}
+
++ (NSString *)stringForIceGatheringState:(RTCIceGatheringState)state {
+  switch (state) {
+    case RTCIceGatheringStateNew:
+      return @"NEW";
+    case RTCIceGatheringStateGathering:
+      return @"GATHERING";
+    case RTCIceGatheringStateComplete:
+      return @"COMPLETE";
+  }
+}
+
++ (webrtc::PeerConnectionInterface::StatsOutputLevel)
+    nativeStatsOutputLevelForLevel:(RTCStatsOutputLevel)level {
+  switch (level) {
+    case RTCStatsOutputLevelStandard:
+      return webrtc::PeerConnectionInterface::kStatsOutputLevelStandard;
+    case RTCStatsOutputLevelDebug:
+      return webrtc::PeerConnectionInterface::kStatsOutputLevelDebug;
+  }
+}
+
+- (rtc::scoped_refptr<webrtc::PeerConnectionInterface>)nativePeerConnection {
+  return _peerConnection;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Native.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Native.h
new file mode 100644
index 0000000..60aa08f
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Native.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCPeerConnectionFactory.h"
+
+#include "rtc_base/scoped_ref_ptr.h"
+
+namespace webrtc {
+
+class AudioDeviceModule;
+class AudioEncoderFactory;
+class AudioDecoderFactory;
+class VideoEncoderFactory;
+class VideoDecoderFactory;
+class AudioProcessing;
+
+}  // namespace webrtc
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * This class extension exposes methods that work directly with injectable C++ components.
+ */
+@interface RTCPeerConnectionFactory ()
+
+- (instancetype)initNative NS_DESIGNATED_INITIALIZER;
+
+/* Initializer used when WebRTC is compiled with no media support */
+- (instancetype)initWithNoMedia;
+
+/* Initialize object with injectable native audio/video encoder/decoder factories */
+- (instancetype)initWithNativeAudioEncoderFactory:
+                    (rtc::scoped_refptr<webrtc::AudioEncoderFactory>)audioEncoderFactory
+                        nativeAudioDecoderFactory:
+                            (rtc::scoped_refptr<webrtc::AudioDecoderFactory>)audioDecoderFactory
+                        nativeVideoEncoderFactory:
+                            (std::unique_ptr<webrtc::VideoEncoderFactory>)videoEncoderFactory
+                        nativeVideoDecoderFactory:
+                            (std::unique_ptr<webrtc::VideoDecoderFactory>)videoDecoderFactory
+                                audioDeviceModule:
+                                    (nullable webrtc::AudioDeviceModule *)audioDeviceModule
+                            audioProcessingModule:
+                                (rtc::scoped_refptr<webrtc::AudioProcessing>)audioProcessingModule;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Private.h
new file mode 100644
index 0000000..4dc03cf
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Private.h
@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnectionFactory.h"
+
+#include "api/peerconnectioninterface.h"
+#include "rtc_base/scoped_ref_ptr.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCPeerConnectionFactory ()
+
+/**
+ * PeerConnectionFactoryInterface created and held by this
+ * RTCPeerConnectionFactory object. This is needed to pass to the underlying
+ * C++ APIs.
+ */
+@property(nonatomic, readonly)
+    rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
+        nativeFactory;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
new file mode 100644
index 0000000..a5faeae
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2015 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
+
+@class RTCAudioSource;
+@class RTCAudioTrack;
+@class RTCConfiguration;
+@class RTCMediaConstraints;
+@class RTCMediaStream;
+@class RTCPeerConnection;
+@class RTCVideoSource;
+@class RTCVideoTrack;
+@class RTCPeerConnectionFactoryOptions;
+@protocol RTCPeerConnectionDelegate;
+@protocol RTCVideoDecoderFactory;
+@protocol RTCVideoEncoderFactory;
+
+RTC_EXPORT
+@interface RTCPeerConnectionFactory : NSObject
+
+/* Initialize object with default H264 video encoder/decoder factories */
+- (instancetype)init;
+
+/* Initialize object with injectable video encoder/decoder factories */
+- (instancetype)initWithEncoderFactory:(nullable id<RTCVideoEncoderFactory>)encoderFactory
+                        decoderFactory:(nullable id<RTCVideoDecoderFactory>)decoderFactory;
+
+/** Initialize an RTCAudioSource with constraints. */
+- (RTCAudioSource *)audioSourceWithConstraints:(nullable RTCMediaConstraints *)constraints;
+
+/** Initialize an RTCAudioTrack with an id. Convenience ctor to use an audio source with no
+ *  constraints.
+ */
+- (RTCAudioTrack *)audioTrackWithTrackId:(NSString *)trackId;
+
+/** Initialize an RTCAudioTrack with a source and an id. */
+- (RTCAudioTrack *)audioTrackWithSource:(RTCAudioSource *)source trackId:(NSString *)trackId;
+
+/** Initialize a generic RTCVideoSource. The RTCVideoSource should be passed to a RTCVideoCapturer
+ *  implementation, e.g. RTCCameraVideoCapturer, in order to produce frames.
+ */
+- (RTCVideoSource *)videoSource;
+
+/** Initialize an RTCVideoTrack with a source and an id. */
+- (RTCVideoTrack *)videoTrackWithSource:(RTCVideoSource *)source trackId:(NSString *)trackId;
+
+/** Initialize an RTCMediaStream with an id. */
+- (RTCMediaStream *)mediaStreamWithStreamId:(NSString *)streamId;
+
+/** Initialize an RTCPeerConnection with a configuration, constraints, and
+ *  delegate.
+ */
+- (RTCPeerConnection *)peerConnectionWithConfiguration:(RTCConfiguration *)configuration
+                                           constraints:(RTCMediaConstraints *)constraints
+                                              delegate:
+                                                  (nullable id<RTCPeerConnectionDelegate>)delegate;
+
+/** Set the options to be used for subsequently created RTCPeerConnections */
+- (void)setOptions:(nonnull RTCPeerConnectionFactoryOptions *)options;
+
+/** Start an AecDump recording. This API call will likely change in the future. */
+- (BOOL)startAecDumpWithFilePath:(NSString *)filePath maxSizeInBytes:(int64_t)maxSizeInBytes;
+
+/* Stop an active AecDump recording */
+- (void)stopAecDump;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
new file mode 100644
index 0000000..403db04
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
@@ -0,0 +1,258 @@
+/*
+ *  Copyright 2015 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 "RTCPeerConnectionFactory+Native.h"
+#import "RTCPeerConnectionFactory+Private.h"
+#import "RTCPeerConnectionFactoryOptions+Private.h"
+
+#import "RTCAudioSource+Private.h"
+#import "RTCAudioTrack+Private.h"
+#import "RTCMediaConstraints+Private.h"
+#import "RTCMediaStream+Private.h"
+#import "RTCPeerConnection+Private.h"
+#import "RTCVideoSource+Private.h"
+#import "RTCVideoTrack+Private.h"
+#import "base/RTCLogging.h"
+#import "base/RTCVideoDecoderFactory.h"
+#import "base/RTCVideoEncoderFactory.h"
+#import "helpers/NSString+StdString.h"
+#ifndef HAVE_NO_MEDIA
+#import "components/video_codec/RTCVideoDecoderFactoryH264.h"
+#import "components/video_codec/RTCVideoEncoderFactoryH264.h"
+// The no-media version PeerConnectionFactory doesn't depend on these files, but the gn check tool
+// is not smart enough to take the #ifdef into account.
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"     // nogncheck
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"     // nogncheck
+#include "media/engine/convert_legacy_video_factory.h"          // nogncheck
+#include "modules/audio_device/include/audio_device.h"          // nogncheck
+#include "modules/audio_processing/include/audio_processing.h"  // nogncheck
+
+#include "sdk/objc/native/api/video_decoder_factory.h"
+#include "sdk/objc/native/api/video_encoder_factory.h"
+#include "sdk/objc/native/src/objc_video_decoder_factory.h"
+#include "sdk/objc/native/src/objc_video_encoder_factory.h"
+#endif
+
+#if defined(WEBRTC_IOS)
+#import "sdk/objc/native/api/audio_device_module.h"
+#endif
+
+// Adding the nogncheck to disable the including header check.
+// The no-media version PeerConnectionFactory doesn't depend on media related
+// C++ target.
+// TODO(zhihuang): Remove nogncheck once MediaEngineInterface is moved to C++
+// API layer.
+#include "absl/memory/memory.h"
+#include "media/engine/webrtcmediaengine.h"  // nogncheck
+
+@implementation RTCPeerConnectionFactory {
+  std::unique_ptr<rtc::Thread> _networkThread;
+  std::unique_ptr<rtc::Thread> _workerThread;
+  std::unique_ptr<rtc::Thread> _signalingThread;
+  BOOL _hasStartedAecDump;
+}
+
+@synthesize nativeFactory = _nativeFactory;
+
+- (rtc::scoped_refptr<webrtc::AudioDeviceModule>)audioDeviceModule {
+#if defined(WEBRTC_IOS)
+  return webrtc::CreateAudioDeviceModule();
+#else
+  return nullptr;
+#endif
+}
+
+- (instancetype)init {
+#ifdef HAVE_NO_MEDIA
+  return [self initWithNoMedia];
+#else
+  return [self initWithNativeAudioEncoderFactory:webrtc::CreateBuiltinAudioEncoderFactory()
+                       nativeAudioDecoderFactory:webrtc::CreateBuiltinAudioDecoderFactory()
+                       nativeVideoEncoderFactory:webrtc::ObjCToNativeVideoEncoderFactory(
+                                                     [[RTCVideoEncoderFactoryH264 alloc] init])
+                       nativeVideoDecoderFactory:webrtc::ObjCToNativeVideoDecoderFactory(
+                                                     [[RTCVideoDecoderFactoryH264 alloc] init])
+                               audioDeviceModule:[self audioDeviceModule]
+                           audioProcessingModule:nullptr];
+#endif
+}
+
+- (instancetype)initWithEncoderFactory:(nullable id<RTCVideoEncoderFactory>)encoderFactory
+                        decoderFactory:(nullable id<RTCVideoDecoderFactory>)decoderFactory {
+#ifdef HAVE_NO_MEDIA
+  return [self initWithNoMedia];
+#else
+  std::unique_ptr<webrtc::VideoEncoderFactory> native_encoder_factory;
+  std::unique_ptr<webrtc::VideoDecoderFactory> native_decoder_factory;
+  if (encoderFactory) {
+    native_encoder_factory = webrtc::ObjCToNativeVideoEncoderFactory(encoderFactory);
+  }
+  if (decoderFactory) {
+    native_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory);
+  }
+  return [self initWithNativeAudioEncoderFactory:webrtc::CreateBuiltinAudioEncoderFactory()
+                       nativeAudioDecoderFactory:webrtc::CreateBuiltinAudioDecoderFactory()
+                       nativeVideoEncoderFactory:std::move(native_encoder_factory)
+                       nativeVideoDecoderFactory:std::move(native_decoder_factory)
+                               audioDeviceModule:[self audioDeviceModule]
+                           audioProcessingModule:nullptr];
+#endif
+}
+
+- (instancetype)initNative {
+  if (self = [super init]) {
+    _networkThread = rtc::Thread::CreateWithSocketServer();
+    _networkThread->SetName("network_thread", _networkThread.get());
+    BOOL result = _networkThread->Start();
+    NSAssert(result, @"Failed to start network thread.");
+
+    _workerThread = rtc::Thread::Create();
+    _workerThread->SetName("worker_thread", _workerThread.get());
+    result = _workerThread->Start();
+    NSAssert(result, @"Failed to start worker thread.");
+
+    _signalingThread = rtc::Thread::Create();
+    _signalingThread->SetName("signaling_thread", _signalingThread.get());
+    result = _signalingThread->Start();
+    NSAssert(result, @"Failed to start signaling thread.");
+  }
+  return self;
+}
+
+- (instancetype)initWithNoMedia {
+  if (self = [self initNative]) {
+    _nativeFactory = webrtc::CreateModularPeerConnectionFactory(
+        _networkThread.get(),
+        _workerThread.get(),
+        _signalingThread.get(),
+        std::unique_ptr<cricket::MediaEngineInterface>(),
+        std::unique_ptr<webrtc::CallFactoryInterface>(),
+        std::unique_ptr<webrtc::RtcEventLogFactoryInterface>());
+    NSAssert(_nativeFactory, @"Failed to initialize PeerConnectionFactory!");
+  }
+  return self;
+}
+
+- (instancetype)initWithNativeAudioEncoderFactory:
+                    (rtc::scoped_refptr<webrtc::AudioEncoderFactory>)audioEncoderFactory
+                        nativeAudioDecoderFactory:
+                            (rtc::scoped_refptr<webrtc::AudioDecoderFactory>)audioDecoderFactory
+                        nativeVideoEncoderFactory:
+                            (std::unique_ptr<webrtc::VideoEncoderFactory>)videoEncoderFactory
+                        nativeVideoDecoderFactory:
+                            (std::unique_ptr<webrtc::VideoDecoderFactory>)videoDecoderFactory
+                                audioDeviceModule:
+                                    (nullable webrtc::AudioDeviceModule *)audioDeviceModule
+                            audioProcessingModule:
+                                (rtc::scoped_refptr<webrtc::AudioProcessing>)audioProcessingModule {
+#ifdef HAVE_NO_MEDIA
+  return [self initWithNoMedia];
+#else
+  if (self = [self initNative]) {
+    _nativeFactory = webrtc::CreatePeerConnectionFactory(_networkThread.get(),
+                                                         _workerThread.get(),
+                                                         _signalingThread.get(),
+                                                         audioDeviceModule,
+                                                         audioEncoderFactory,
+                                                         audioDecoderFactory,
+                                                         std::move(videoEncoderFactory),
+                                                         std::move(videoDecoderFactory),
+                                                         nullptr,  // audio mixer
+                                                         audioProcessingModule);
+    NSAssert(_nativeFactory, @"Failed to initialize PeerConnectionFactory!");
+  }
+  return self;
+#endif
+}
+
+- (RTCAudioSource *)audioSourceWithConstraints:(nullable RTCMediaConstraints *)constraints {
+  std::unique_ptr<webrtc::MediaConstraints> nativeConstraints;
+  if (constraints) {
+    nativeConstraints = constraints.nativeConstraints;
+  }
+  cricket::AudioOptions options;
+  CopyConstraintsIntoAudioOptions(nativeConstraints.get(), &options);
+
+  rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
+      _nativeFactory->CreateAudioSource(options);
+  return [[RTCAudioSource alloc] initWithFactory:self nativeAudioSource:source];
+}
+
+- (RTCAudioTrack *)audioTrackWithTrackId:(NSString *)trackId {
+  RTCAudioSource *audioSource = [self audioSourceWithConstraints:nil];
+  return [self audioTrackWithSource:audioSource trackId:trackId];
+}
+
+- (RTCAudioTrack *)audioTrackWithSource:(RTCAudioSource *)source
+                                trackId:(NSString *)trackId {
+  return [[RTCAudioTrack alloc] initWithFactory:self
+                                         source:source
+                                        trackId:trackId];
+}
+
+- (RTCVideoSource *)videoSource {
+  return [[RTCVideoSource alloc] initWithFactory:self
+                                 signalingThread:_signalingThread.get()
+                                    workerThread:_workerThread.get()];
+}
+
+- (RTCVideoTrack *)videoTrackWithSource:(RTCVideoSource *)source
+                                trackId:(NSString *)trackId {
+  return [[RTCVideoTrack alloc] initWithFactory:self
+                                         source:source
+                                        trackId:trackId];
+}
+
+- (RTCMediaStream *)mediaStreamWithStreamId:(NSString *)streamId {
+  return [[RTCMediaStream alloc] initWithFactory:self
+                                        streamId:streamId];
+}
+
+- (RTCPeerConnection *)peerConnectionWithConfiguration:
+    (RTCConfiguration *)configuration
+                                           constraints:
+    (RTCMediaConstraints *)constraints
+                                              delegate:
+    (nullable id<RTCPeerConnectionDelegate>)delegate {
+  return [[RTCPeerConnection alloc] initWithFactory:self
+                                      configuration:configuration
+                                        constraints:constraints
+                                           delegate:delegate];
+}
+
+- (void)setOptions:(nonnull RTCPeerConnectionFactoryOptions *)options {
+  RTC_DCHECK(options != nil);
+  _nativeFactory->SetOptions(options.nativeOptions);
+}
+
+- (BOOL)startAecDumpWithFilePath:(NSString *)filePath
+                  maxSizeInBytes:(int64_t)maxSizeInBytes {
+  RTC_DCHECK(filePath.length);
+  RTC_DCHECK_GT(maxSizeInBytes, 0);
+
+  if (_hasStartedAecDump) {
+    RTCLogError(@"Aec dump already started.");
+    return NO;
+  }
+  int fd = open(filePath.UTF8String, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+  if (fd < 0) {
+    RTCLogError(@"Error opening file: %@. Error: %d", filePath, errno);
+    return NO;
+  }
+  _hasStartedAecDump = _nativeFactory->StartAecDump(fd, maxSizeInBytes);
+  return _hasStartedAecDump;
+}
+
+- (void)stopAecDump {
+  _nativeFactory->StopAecDump();
+  _hasStartedAecDump = NO;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.h
new file mode 100644
index 0000000..070a0e7
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.h
@@ -0,0 +1,21 @@
+/*
+ *  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 "RTCPeerConnectionFactoryBuilder.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCPeerConnectionFactoryBuilder (DefaultComponents)
+
++ (RTCPeerConnectionFactoryBuilder *)defaultBuilder;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.mm
new file mode 100644
index 0000000..3bb75ee
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder+DefaultComponents.mm
@@ -0,0 +1,49 @@
+/*
+ *  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 "RTCPeerConnectionFactory+Native.h"
+#import "RTCPeerConnectionFactoryBuilder+DefaultComponents.h"
+
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#import "components/video_codec/RTCVideoDecoderFactoryH264.h"
+#import "components/video_codec/RTCVideoEncoderFactoryH264.h"
+#include "sdk/objc/native/api/video_decoder_factory.h"
+#include "sdk/objc/native/api/video_encoder_factory.h"
+
+#if defined(WEBRTC_IOS)
+#import "sdk/objc/native/api/audio_device_module.h"
+#endif
+
+@implementation RTCPeerConnectionFactoryBuilder (DefaultComponents)
+
++ (RTCPeerConnectionFactoryBuilder *)defaultBuilder {
+  RTCPeerConnectionFactoryBuilder *builder = [[RTCPeerConnectionFactoryBuilder alloc] init];
+  auto audioEncoderFactory = webrtc::CreateBuiltinAudioEncoderFactory();
+  [builder setAudioEncoderFactory:audioEncoderFactory];
+
+  auto audioDecoderFactory = webrtc::CreateBuiltinAudioDecoderFactory();
+  [builder setAudioDecoderFactory:audioDecoderFactory];
+
+  auto videoEncoderFactory =
+      webrtc::ObjCToNativeVideoEncoderFactory([[RTCVideoEncoderFactoryH264 alloc] init]);
+  [builder setVideoEncoderFactory:std::move(videoEncoderFactory)];
+
+  auto videoDecoderFactory =
+      webrtc::ObjCToNativeVideoDecoderFactory([[RTCVideoDecoderFactoryH264 alloc] init]);
+  [builder setVideoDecoderFactory:std::move(videoDecoderFactory)];
+
+#if defined(WEBRTC_IOS)
+  [builder setAudioDeviceModule:webrtc::CreateAudioDeviceModule()];
+#endif
+  return builder;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.h
new file mode 100644
index 0000000..cca5446
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.h
@@ -0,0 +1,48 @@
+/*
+ *  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 "RTCPeerConnectionFactory.h"
+
+#include "rtc_base/scoped_ref_ptr.h"
+
+namespace webrtc {
+
+class AudioDeviceModule;
+class AudioEncoderFactory;
+class AudioDecoderFactory;
+class VideoEncoderFactory;
+class VideoDecoderFactory;
+class AudioProcessing;
+
+}  // namespace webrtc
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCPeerConnectionFactoryBuilder : NSObject
+
++ (RTCPeerConnectionFactoryBuilder *)builder;
+
+- (RTCPeerConnectionFactory *)createPeerConnectionFactory;
+
+- (void)setVideoEncoderFactory:(std::unique_ptr<webrtc::VideoEncoderFactory>)videoEncoderFactory;
+
+- (void)setVideoDecoderFactory:(std::unique_ptr<webrtc::VideoDecoderFactory>)videoDecoderFactory;
+
+- (void)setAudioEncoderFactory:(rtc::scoped_refptr<webrtc::AudioEncoderFactory>)audioEncoderFactory;
+
+- (void)setAudioDecoderFactory:(rtc::scoped_refptr<webrtc::AudioDecoderFactory>)audioDecoderFactory;
+
+- (void)setAudioDeviceModule:(rtc::scoped_refptr<webrtc::AudioDeviceModule>)audioDeviceModule;
+
+- (void)setAudioProcessingModule:(rtc::scoped_refptr<webrtc::AudioProcessing>)audioProcessingModule;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.mm
new file mode 100644
index 0000000..a26a639
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryBuilder.mm
@@ -0,0 +1,71 @@
+/*
+ *  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 "RTCPeerConnectionFactoryBuilder.h"
+#import "RTCPeerConnectionFactory+Native.h"
+
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "modules/audio_device/include/audio_device.h"
+#include "modules/audio_processing/include/audio_processing.h"
+
+@implementation RTCPeerConnectionFactoryBuilder {
+  std::unique_ptr<webrtc::VideoEncoderFactory> _videoEncoderFactory;
+  std::unique_ptr<webrtc::VideoDecoderFactory> _videoDecoderFactory;
+  rtc::scoped_refptr<webrtc::AudioEncoderFactory> _audioEncoderFactory;
+  rtc::scoped_refptr<webrtc::AudioDecoderFactory> _audioDecoderFactory;
+  rtc::scoped_refptr<webrtc::AudioDeviceModule> _audioDeviceModule;
+  rtc::scoped_refptr<webrtc::AudioProcessing> _audioProcessingModule;
+}
+
++ (RTCPeerConnectionFactoryBuilder *)builder {
+  return [[RTCPeerConnectionFactoryBuilder alloc] init];
+}
+
+- (RTCPeerConnectionFactory *)createPeerConnectionFactory {
+  RTCPeerConnectionFactory *factory = [RTCPeerConnectionFactory alloc];
+  return [factory initWithNativeAudioEncoderFactory:_audioEncoderFactory
+                          nativeAudioDecoderFactory:_audioDecoderFactory
+                          nativeVideoEncoderFactory:std::move(_videoEncoderFactory)
+                          nativeVideoDecoderFactory:std::move(_videoDecoderFactory)
+                                  audioDeviceModule:_audioDeviceModule
+                              audioProcessingModule:_audioProcessingModule];
+}
+
+- (void)setVideoEncoderFactory:(std::unique_ptr<webrtc::VideoEncoderFactory>)videoEncoderFactory {
+  _videoEncoderFactory = std::move(videoEncoderFactory);
+}
+
+- (void)setVideoDecoderFactory:(std::unique_ptr<webrtc::VideoDecoderFactory>)videoDecoderFactory {
+  _videoDecoderFactory = std::move(videoDecoderFactory);
+}
+
+- (void)setAudioEncoderFactory:
+        (rtc::scoped_refptr<webrtc::AudioEncoderFactory>)audioEncoderFactory {
+  _audioEncoderFactory = audioEncoderFactory;
+}
+
+- (void)setAudioDecoderFactory:
+        (rtc::scoped_refptr<webrtc::AudioDecoderFactory>)audioDecoderFactory {
+  _audioDecoderFactory = audioDecoderFactory;
+}
+
+- (void)setAudioDeviceModule:(rtc::scoped_refptr<webrtc::AudioDeviceModule>)audioDeviceModule {
+  _audioDeviceModule = audioDeviceModule;
+}
+
+- (void)setAudioProcessingModule:
+        (rtc::scoped_refptr<webrtc::AudioProcessing>)audioProcessingModule {
+  _audioProcessingModule = audioProcessingModule;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions+Private.h
new file mode 100644
index 0000000..2ccbd1c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions+Private.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCPeerConnectionFactoryOptions.h"
+
+#include "api/peerconnectioninterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCPeerConnectionFactoryOptions ()
+
+/** Returns the equivalent native PeerConnectionFactoryInterface::Options
+ * structure. */
+@property(nonatomic, readonly)
+    webrtc::PeerConnectionFactoryInterface::Options nativeOptions;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.h
new file mode 100644
index 0000000..26a743b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCPeerConnectionFactoryOptions : NSObject
+
+@property(nonatomic, assign) BOOL disableEncryption;
+
+@property(nonatomic, assign) BOOL disableNetworkMonitor;
+
+@property(nonatomic, assign) BOOL ignoreLoopbackNetworkAdapter;
+
+@property(nonatomic, assign) BOOL ignoreVPNNetworkAdapter;
+
+@property(nonatomic, assign) BOOL ignoreCellularNetworkAdapter;
+
+@property(nonatomic, assign) BOOL ignoreWiFiNetworkAdapter;
+
+@property(nonatomic, assign) BOOL ignoreEthernetNetworkAdapter;
+
+@property(nonatomic, assign) BOOL enableAes128Sha1_32CryptoCipher;
+
+@property(nonatomic, assign) BOOL enableGcmCryptoSuites;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.mm
new file mode 100644
index 0000000..103a130
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactoryOptions.mm
@@ -0,0 +1,61 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCPeerConnectionFactoryOptions+Private.h"
+
+#include "rtc_base/network_constants.h"
+
+namespace {
+
+void setNetworkBit(webrtc::PeerConnectionFactoryInterface::Options* options,
+                   rtc::AdapterType type,
+                   bool ignore) {
+  if (ignore) {
+    options->network_ignore_mask |= type;
+  } else {
+    options->network_ignore_mask &= ~type;
+  }
+}
+}  // namespace
+
+@implementation RTCPeerConnectionFactoryOptions
+
+@synthesize disableEncryption = _disableEncryption;
+@synthesize disableNetworkMonitor = _disableNetworkMonitor;
+@synthesize ignoreLoopbackNetworkAdapter = _ignoreLoopbackNetworkAdapter;
+@synthesize ignoreVPNNetworkAdapter = _ignoreVPNNetworkAdapter;
+@synthesize ignoreCellularNetworkAdapter = _ignoreCellularNetworkAdapter;
+@synthesize ignoreWiFiNetworkAdapter = _ignoreWiFiNetworkAdapter;
+@synthesize ignoreEthernetNetworkAdapter = _ignoreEthernetNetworkAdapter;
+@synthesize enableAes128Sha1_32CryptoCipher = _enableAes128Sha1_32CryptoCipher;
+@synthesize enableGcmCryptoSuites = _enableGcmCryptoSuites;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (webrtc::PeerConnectionFactoryInterface::Options)nativeOptions {
+  webrtc::PeerConnectionFactoryInterface::Options options;
+  options.disable_encryption = self.disableEncryption;
+  options.disable_network_monitor = self.disableNetworkMonitor;
+
+  setNetworkBit(&options, rtc::ADAPTER_TYPE_LOOPBACK, self.ignoreLoopbackNetworkAdapter);
+  setNetworkBit(&options, rtc::ADAPTER_TYPE_VPN, self.ignoreVPNNetworkAdapter);
+  setNetworkBit(&options, rtc::ADAPTER_TYPE_CELLULAR, self.ignoreCellularNetworkAdapter);
+  setNetworkBit(&options, rtc::ADAPTER_TYPE_WIFI, self.ignoreWiFiNetworkAdapter);
+  setNetworkBit(&options, rtc::ADAPTER_TYPE_ETHERNET, self.ignoreEthernetNetworkAdapter);
+
+  options.crypto_options.enable_aes128_sha1_32_crypto_cipher = self.enableAes128Sha1_32CryptoCipher;
+  options.crypto_options.enable_gcm_crypto_suites = self.enableGcmCryptoSuites;
+
+  return options;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtcpParameters+Private.h b/sdk/objc/api/peerconnection/RTCRtcpParameters+Private.h
new file mode 100644
index 0000000..540601b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtcpParameters+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  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 "RTCRtcpParameters.h"
+
+#include "api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtcpParameters ()
+
+/** Returns the equivalent native RtcpParameters structure. */
+@property(nonatomic, readonly) webrtc::RtcpParameters nativeParameters;
+
+/** Initialize the object with a native RtcpParameters structure. */
+- (instancetype)initWithNativeParameters:(const webrtc::RtcpParameters &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtcpParameters.h b/sdk/objc/api/peerconnection/RTCRtcpParameters.h
new file mode 100644
index 0000000..2f4c43b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtcpParameters.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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCRtcpParameters : NSObject
+
+/** The Canonical Name used by RTCP. */
+@property(nonatomic, readonly, copy) NSString *cname;
+
+/** Whether reduced size RTCP is configured or compound RTCP. */
+@property(nonatomic, assign) BOOL isReducedSize;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtcpParameters.mm b/sdk/objc/api/peerconnection/RTCRtcpParameters.mm
new file mode 100644
index 0000000..0c33dda
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtcpParameters.mm
@@ -0,0 +1,39 @@
+/*
+ *  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 "RTCRtcpParameters+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCRtcpParameters
+
+@synthesize cname = _cname;
+@synthesize isReducedSize = _isReducedSize;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:(const webrtc::RtcpParameters &)nativeParameters {
+  if (self = [self init]) {
+    _cname = [NSString stringForStdString:nativeParameters.cname];
+    _isReducedSize = nativeParameters.reduced_size;
+  }
+  return self;
+}
+
+- (webrtc::RtcpParameters)nativeParameters {
+  webrtc::RtcpParameters parameters;
+  parameters.cname = [NSString stdStringForString:_cname];
+  parameters.reduced_size = _isReducedSize;
+  return parameters;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecParameters+Private.h b/sdk/objc/api/peerconnection/RTCRtpCodecParameters+Private.h
new file mode 100644
index 0000000..3759a27
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecParameters+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2016 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 "RTCRtpCodecParameters.h"
+
+#include "api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtpCodecParameters ()
+
+/** Returns the equivalent native RtpCodecParameters structure. */
+@property(nonatomic, readonly) webrtc::RtpCodecParameters nativeParameters;
+
+/** Initialize the object with a native RtpCodecParameters structure. */
+- (instancetype)initWithNativeParameters:(const webrtc::RtpCodecParameters &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecParameters.h b/sdk/objc/api/peerconnection/RTCRtpCodecParameters.h
new file mode 100644
index 0000000..cb69a37
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecParameters.h
@@ -0,0 +1,73 @@
+/*
+ *  Copyright 2016 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
+
+RTC_EXTERN const NSString *const kRTCRtxCodecName;
+RTC_EXTERN const NSString *const kRTCRedCodecName;
+RTC_EXTERN const NSString *const kRTCUlpfecCodecName;
+RTC_EXTERN const NSString *const kRTCFlexfecCodecName;
+RTC_EXTERN const NSString *const kRTCOpusCodecName;
+RTC_EXTERN const NSString *const kRTCIsacCodecName;
+RTC_EXTERN const NSString *const kRTCL16CodecName;
+RTC_EXTERN const NSString *const kRTCG722CodecName;
+RTC_EXTERN const NSString *const kRTCIlbcCodecName;
+RTC_EXTERN const NSString *const kRTCPcmuCodecName;
+RTC_EXTERN const NSString *const kRTCPcmaCodecName;
+RTC_EXTERN const NSString *const kRTCDtmfCodecName;
+RTC_EXTERN const NSString *const kRTCComfortNoiseCodecName;
+RTC_EXTERN const NSString *const kRTCVp8CodecName;
+RTC_EXTERN const NSString *const kRTCVp9CodecName;
+RTC_EXTERN const NSString *const kRTCH264CodecName;
+
+/** Defined in http://w3c.github.io/webrtc-pc/#idl-def-RTCRtpCodecParameters */
+RTC_EXPORT
+@interface RTCRtpCodecParameters : NSObject
+
+/** The RTP payload type. */
+@property(nonatomic, assign) int payloadType;
+
+/**
+ * The codec MIME subtype. Valid types are listed in:
+ * http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-2
+ *
+ * Several supported types are represented by the constants above.
+ */
+@property(nonatomic, readonly, nonnull) NSString *name;
+
+/**
+ * The media type of this codec. Equivalent to MIME top-level type.
+ *
+ * Valid values are kRTCMediaStreamTrackKindAudio and
+ * kRTCMediaStreamTrackKindVideo.
+ */
+@property(nonatomic, readonly, nonnull) NSString *kind;
+
+/** The codec clock rate expressed in Hertz. */
+@property(nonatomic, readonly, nullable) NSNumber *clockRate;
+
+/**
+ * The number of channels (mono=1, stereo=2).
+ * Set to null for video codecs.
+ **/
+@property(nonatomic, readonly, nullable) NSNumber *numChannels;
+
+/** The "format specific parameters" field from the "a=fmtp" line in the SDP */
+@property(nonatomic, readonly, nonnull) NSDictionary *parameters;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpCodecParameters.mm b/sdk/objc/api/peerconnection/RTCRtpCodecParameters.mm
new file mode 100644
index 0000000..d555bea
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpCodecParameters.mm
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 2016 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 "RTCRtpCodecParameters+Private.h"
+
+#import "RTCMediaStreamTrack.h"
+#import "helpers/NSString+StdString.h"
+
+#include "media/base/mediaconstants.h"
+#include "rtc_base/checks.h"
+
+const NSString * const kRTCRtxCodecName = @(cricket::kRtxCodecName);
+const NSString * const kRTCRedCodecName = @(cricket::kRedCodecName);
+const NSString * const kRTCUlpfecCodecName = @(cricket::kUlpfecCodecName);
+const NSString * const kRTCFlexfecCodecName = @(cricket::kFlexfecCodecName);
+const NSString * const kRTCOpusCodecName = @(cricket::kOpusCodecName);
+const NSString * const kRTCIsacCodecName = @(cricket::kIsacCodecName);
+const NSString * const kRTCL16CodecName  = @(cricket::kL16CodecName);
+const NSString * const kRTCG722CodecName = @(cricket::kG722CodecName);
+const NSString * const kRTCIlbcCodecName = @(cricket::kIlbcCodecName);
+const NSString * const kRTCPcmuCodecName = @(cricket::kPcmuCodecName);
+const NSString * const kRTCPcmaCodecName = @(cricket::kPcmaCodecName);
+const NSString * const kRTCDtmfCodecName = @(cricket::kDtmfCodecName);
+const NSString * const kRTCComfortNoiseCodecName =
+    @(cricket::kComfortNoiseCodecName);
+const NSString * const kRTCVp8CodecName = @(cricket::kVp8CodecName);
+const NSString * const kRTCVp9CodecName = @(cricket::kVp9CodecName);
+const NSString * const kRTCH264CodecName = @(cricket::kH264CodecName);
+
+@implementation RTCRtpCodecParameters
+
+@synthesize payloadType = _payloadType;
+@synthesize name = _name;
+@synthesize kind = _kind;
+@synthesize clockRate = _clockRate;
+@synthesize numChannels = _numChannels;
+@synthesize parameters = _parameters;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:
+    (const webrtc::RtpCodecParameters &)nativeParameters {
+  if (self = [self init]) {
+    _payloadType = nativeParameters.payload_type;
+    _name = [NSString stringForStdString:nativeParameters.name];
+    switch (nativeParameters.kind) {
+      case cricket::MEDIA_TYPE_AUDIO:
+        _kind = kRTCMediaStreamTrackKindAudio;
+        break;
+      case cricket::MEDIA_TYPE_VIDEO:
+        _kind = kRTCMediaStreamTrackKindVideo;
+        break;
+      case cricket::MEDIA_TYPE_DATA:
+        RTC_NOTREACHED();
+        break;
+    }
+    if (nativeParameters.clock_rate) {
+      _clockRate = [NSNumber numberWithInt:*nativeParameters.clock_rate];
+    }
+    if (nativeParameters.num_channels) {
+      _numChannels = [NSNumber numberWithInt:*nativeParameters.num_channels];
+    }
+    NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
+    for (const auto &parameter : nativeParameters.parameters) {
+      [parameters setObject:[NSString stringForStdString:parameter.second]
+                     forKey:[NSString stringForStdString:parameter.first]];
+    }
+    _parameters = parameters;
+  }
+  return self;
+}
+
+- (webrtc::RtpCodecParameters)nativeParameters {
+  webrtc::RtpCodecParameters parameters;
+  parameters.payload_type = _payloadType;
+  parameters.name = [NSString stdStringForString:_name];
+  // NSString pointer comparison is safe here since "kind" is readonly and only
+  // populated above.
+  if (_kind == kRTCMediaStreamTrackKindAudio) {
+    parameters.kind = cricket::MEDIA_TYPE_AUDIO;
+  } else if (_kind == kRTCMediaStreamTrackKindVideo) {
+    parameters.kind = cricket::MEDIA_TYPE_VIDEO;
+  } else {
+    RTC_NOTREACHED();
+  }
+  if (_clockRate != nil) {
+    parameters.clock_rate = absl::optional<int>(_clockRate.intValue);
+  }
+  if (_numChannels != nil) {
+    parameters.num_channels = absl::optional<int>(_numChannels.intValue);
+  }
+  for (NSString *paramKey in _parameters.allKeys) {
+    std::string key = [NSString stdStringForString:paramKey];
+    std::string value = [NSString stdStringForString:_parameters[paramKey]];
+    parameters.parameters[key] = value;
+  }
+  return parameters;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpEncodingParameters+Private.h b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters+Private.h
new file mode 100644
index 0000000..fe60948
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2016 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 "RTCRtpEncodingParameters.h"
+
+#include "api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtpEncodingParameters ()
+
+/** Returns the equivalent native RtpEncodingParameters structure. */
+@property(nonatomic, readonly) webrtc::RtpEncodingParameters nativeParameters;
+
+/** Initialize the object with a native RtpEncodingParameters structure. */
+- (instancetype)initWithNativeParameters:(const webrtc::RtpEncodingParameters &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.h b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.h
new file mode 100644
index 0000000..900b379
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 2016 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
+
+RTC_EXPORT
+@interface RTCRtpEncodingParameters : NSObject
+
+/** Controls whether the encoding is currently transmitted. */
+@property(nonatomic, assign) BOOL isActive;
+
+/** The maximum bitrate to use for the encoding, or nil if there is no
+ *  limit.
+ */
+@property(nonatomic, copy, nullable) NSNumber *maxBitrateBps;
+
+/** The minimum bitrate to use for the encoding, or nil if there is no
+ *  limit.
+ *
+ *  Not implemented.
+ */
+@property(nonatomic, copy, nullable) NSNumber *minBitrateBps;
+
+/** The SSRC being used by this encoding. */
+@property(nonatomic, readonly, nullable) NSNumber *ssrc;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.mm b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.mm
new file mode 100644
index 0000000..299e318
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpEncodingParameters.mm
@@ -0,0 +1,58 @@
+/*
+ *  Copyright 2016 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 "RTCRtpEncodingParameters+Private.h"
+
+@implementation RTCRtpEncodingParameters
+
+@synthesize isActive = _isActive;
+@synthesize maxBitrateBps = _maxBitrateBps;
+@synthesize minBitrateBps = _minBitrateBps;
+@synthesize ssrc = _ssrc;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:
+    (const webrtc::RtpEncodingParameters &)nativeParameters {
+  if (self = [self init]) {
+    _isActive = nativeParameters.active;
+    if (nativeParameters.max_bitrate_bps) {
+      _maxBitrateBps =
+          [NSNumber numberWithInt:*nativeParameters.max_bitrate_bps];
+    }
+    if (nativeParameters.min_bitrate_bps) {
+      _minBitrateBps =
+          [NSNumber numberWithInt:*nativeParameters.min_bitrate_bps];
+    }
+    if (nativeParameters.ssrc) {
+      _ssrc = [NSNumber numberWithUnsignedLong:*nativeParameters.ssrc];
+    }
+  }
+  return self;
+}
+
+- (webrtc::RtpEncodingParameters)nativeParameters {
+  webrtc::RtpEncodingParameters parameters;
+  parameters.active = _isActive;
+  if (_maxBitrateBps != nil) {
+    parameters.max_bitrate_bps = absl::optional<int>(_maxBitrateBps.intValue);
+  }
+  if (_minBitrateBps != nil) {
+    parameters.min_bitrate_bps = absl::optional<int>(_minBitrateBps.intValue);
+  }
+  if (_ssrc != nil) {
+    parameters.ssrc = absl::optional<uint32_t>(_ssrc.unsignedLongValue);
+  }
+  return parameters;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.h b/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.h
new file mode 100644
index 0000000..cfb7fb1
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "base/RTCRtpFragmentationHeader.h"
+
+#include "modules/include/module_common_types.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/* Interfaces for converting to/from internal C++ formats. */
+@interface RTCRtpFragmentationHeader (Private)
+
+- (instancetype)initWithNativeFragmentationHeader:
+        (const webrtc::RTPFragmentationHeader *__nullable)fragmentationHeader;
+- (std::unique_ptr<webrtc::RTPFragmentationHeader>)createNativeFragmentationHeader;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.mm b/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.mm
new file mode 100644
index 0000000..e2f4b10
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpFragmentationHeader+Private.mm
@@ -0,0 +1,57 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCRtpFragmentationHeader+Private.h"
+
+#include "modules/include/module_common_types.h"
+
+@implementation RTCRtpFragmentationHeader (Private)
+
+- (instancetype)initWithNativeFragmentationHeader:
+        (const webrtc::RTPFragmentationHeader *)fragmentationHeader {
+  if (self = [super init]) {
+    if (fragmentationHeader) {
+      int count = fragmentationHeader->fragmentationVectorSize;
+      NSMutableArray *offsets = [NSMutableArray array];
+      NSMutableArray *lengths = [NSMutableArray array];
+      NSMutableArray *timeDiffs = [NSMutableArray array];
+      NSMutableArray *plTypes = [NSMutableArray array];
+      for (int i = 0; i < count; ++i) {
+        [offsets addObject:@(fragmentationHeader->fragmentationOffset[i])];
+        [lengths addObject:@(fragmentationHeader->fragmentationLength[i])];
+        [timeDiffs addObject:@(fragmentationHeader->fragmentationTimeDiff[i])];
+        [plTypes addObject:@(fragmentationHeader->fragmentationPlType[i])];
+      }
+      self.fragmentationOffset = [offsets copy];
+      self.fragmentationLength = [lengths copy];
+      self.fragmentationTimeDiff = [timeDiffs copy];
+      self.fragmentationPlType = [plTypes copy];
+    }
+  }
+
+  return self;
+}
+
+- (std::unique_ptr<webrtc::RTPFragmentationHeader>)createNativeFragmentationHeader {
+  auto fragmentationHeader =
+      std::unique_ptr<webrtc::RTPFragmentationHeader>(new webrtc::RTPFragmentationHeader);
+  fragmentationHeader->VerifyAndAllocateFragmentationHeader(self.fragmentationOffset.count);
+  for (NSUInteger i = 0; i < self.fragmentationOffset.count; ++i) {
+    fragmentationHeader->fragmentationOffset[i] = (size_t)self.fragmentationOffset[i].unsignedIntValue;
+    fragmentationHeader->fragmentationLength[i] = (size_t)self.fragmentationLength[i].unsignedIntValue;
+    fragmentationHeader->fragmentationTimeDiff[i] =
+        (uint16_t)self.fragmentationOffset[i].unsignedIntValue;
+    fragmentationHeader->fragmentationPlType[i] = (uint8_t)self.fragmentationOffset[i].unsignedIntValue;
+  }
+
+  return fragmentationHeader;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpHeaderExtension+Private.h b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension+Private.h
new file mode 100644
index 0000000..3f1f547
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  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 "RTCRtpHeaderExtension.h"
+
+#include "api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtpHeaderExtension ()
+
+/** Returns the equivalent native RtpExtension structure. */
+@property(nonatomic, readonly) webrtc::RtpExtension nativeParameters;
+
+/** Initialize the object with a native RtpExtension structure. */
+- (instancetype)initWithNativeParameters:(const webrtc::RtpExtension &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.h b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.h
new file mode 100644
index 0000000..8dd80ff
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.h
@@ -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 <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCRtpHeaderExtension : NSObject
+
+/** The URI of the RTP header extension, as defined in RFC5285. */
+@property(nonatomic, readonly, copy) NSString *uri;
+
+/** The value put in the RTP packet to identify the header extension. */
+@property(nonatomic, readonly) int id;
+
+/** Whether the header extension is encrypted or not. */
+@property(nonatomic, readonly, getter=isEncrypted) BOOL encrypted;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.mm b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.mm
new file mode 100644
index 0000000..afc4786
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpHeaderExtension.mm
@@ -0,0 +1,42 @@
+/*
+ *  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 "RTCRtpHeaderExtension+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCRtpHeaderExtension
+
+@synthesize uri = _uri;
+@synthesize id = _id;
+@synthesize encrypted = _encrypted;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:(const webrtc::RtpExtension &)nativeParameters {
+  if (self = [self init]) {
+    _uri = [NSString stringForStdString:nativeParameters.uri];
+    _id = nativeParameters.id;
+    _encrypted = nativeParameters.encrypt;
+  }
+  return self;
+}
+
+- (webrtc::RtpExtension)nativeParameters {
+  webrtc::RtpExtension extension;
+  extension.uri = [NSString stdStringForString:_uri];
+  extension.id = _id;
+  extension.encrypt = _encrypted;
+  return extension;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpParameters+Private.h b/sdk/objc/api/peerconnection/RTCRtpParameters+Private.h
new file mode 100644
index 0000000..0b7aa20
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpParameters+Private.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2016 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 "RTCRtpParameters.h"
+
+#include "api/rtpparameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCRtpParameters ()
+
+/** Returns the equivalent native RtpParameters structure. */
+@property(nonatomic, readonly) webrtc::RtpParameters nativeParameters;
+
+/** Initialize the object with a native RtpParameters structure. */
+- (instancetype)initWithNativeParameters:(const webrtc::RtpParameters &)nativeParameters;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpParameters.h b/sdk/objc/api/peerconnection/RTCRtpParameters.h
new file mode 100644
index 0000000..a4acc9b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpParameters.h
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2016 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"
+#import "RTCRtcpParameters.h"
+#import "RTCRtpCodecParameters.h"
+#import "RTCRtpEncodingParameters.h"
+#import "RTCRtpHeaderExtension.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCRtpParameters : NSObject
+
+/** A unique identifier for the last set of parameters applied. */
+@property(nonatomic, copy) NSString *transactionId;
+
+/** Parameters used for RTCP. */
+@property(nonatomic, readonly, copy) RTCRtcpParameters *rtcp;
+
+/** An array containing parameters for RTP header extensions. */
+@property(nonatomic, readonly, copy) NSArray<RTCRtpHeaderExtension *> *headerExtensions;
+
+/** The currently active encodings in the order of preference. */
+@property(nonatomic, copy) NSArray<RTCRtpEncodingParameters *> *encodings;
+
+/** The negotiated set of send codecs in order of preference. */
+@property(nonatomic, copy) NSArray<RTCRtpCodecParameters *> *codecs;
+
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpParameters.mm b/sdk/objc/api/peerconnection/RTCRtpParameters.mm
new file mode 100644
index 0000000..9b76ac5
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpParameters.mm
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2016 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 "RTCRtpParameters+Private.h"
+
+#import "RTCRtcpParameters+Private.h"
+#import "RTCRtpCodecParameters+Private.h"
+#import "RTCRtpEncodingParameters+Private.h"
+#import "RTCRtpHeaderExtension+Private.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCRtpParameters
+
+@synthesize transactionId = _transactionId;
+@synthesize rtcp = _rtcp;
+@synthesize headerExtensions = _headerExtensions;
+@synthesize encodings = _encodings;
+@synthesize codecs = _codecs;
+
+- (instancetype)init {
+  return [super init];
+}
+
+- (instancetype)initWithNativeParameters:
+    (const webrtc::RtpParameters &)nativeParameters {
+  if (self = [self init]) {
+    _transactionId = [NSString stringForStdString:nativeParameters.transaction_id];
+    _rtcp = [[RTCRtcpParameters alloc] initWithNativeParameters:nativeParameters.rtcp];
+
+    NSMutableArray *headerExtensions = [[NSMutableArray alloc] init];
+    for (const auto &headerExtension : nativeParameters.header_extensions) {
+      [headerExtensions
+          addObject:[[RTCRtpHeaderExtension alloc] initWithNativeParameters:headerExtension]];
+    }
+    _headerExtensions = headerExtensions;
+
+    NSMutableArray *encodings = [[NSMutableArray alloc] init];
+    for (const auto &encoding : nativeParameters.encodings) {
+      [encodings addObject:[[RTCRtpEncodingParameters alloc]
+                               initWithNativeParameters:encoding]];
+    }
+    _encodings = encodings;
+
+    NSMutableArray *codecs = [[NSMutableArray alloc] init];
+    for (const auto &codec : nativeParameters.codecs) {
+      [codecs addObject:[[RTCRtpCodecParameters alloc]
+                            initWithNativeParameters:codec]];
+    }
+    _codecs = codecs;
+  }
+  return self;
+}
+
+- (webrtc::RtpParameters)nativeParameters {
+  webrtc::RtpParameters parameters;
+  parameters.transaction_id = [NSString stdStringForString:_transactionId];
+  parameters.rtcp = [_rtcp nativeParameters];
+  for (RTCRtpHeaderExtension *headerExtension in _headerExtensions) {
+    parameters.header_extensions.push_back(headerExtension.nativeParameters);
+  }
+  for (RTCRtpEncodingParameters *encoding in _encodings) {
+    parameters.encodings.push_back(encoding.nativeParameters);
+  }
+  for (RTCRtpCodecParameters *codec in _codecs) {
+    parameters.codecs.push_back(codec.nativeParameters);
+  }
+  return parameters;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpReceiver+Private.h b/sdk/objc/api/peerconnection/RTCRtpReceiver+Private.h
new file mode 100644
index 0000000..019b5764
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpReceiver+Private.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2016 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 "RTCRtpReceiver.h"
+
+#include "api/rtpreceiverinterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+namespace webrtc {
+
+class RtpReceiverDelegateAdapter : public RtpReceiverObserverInterface {
+ public:
+  RtpReceiverDelegateAdapter(RTCRtpReceiver* receiver);
+
+  void OnFirstPacketReceived(cricket::MediaType media_type) override;
+
+ private:
+  __weak RTCRtpReceiver* receiver_;
+};
+
+}  // namespace webrtc
+
+@interface RTCRtpReceiver ()
+
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::RtpReceiverInterface> nativeRtpReceiver;
+
+/** Initialize an RTCRtpReceiver with a native RtpReceiverInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
+              nativeRtpReceiver:(rtc::scoped_refptr<webrtc::RtpReceiverInterface>)nativeRtpReceiver
+    NS_DESIGNATED_INITIALIZER;
+
++ (RTCRtpMediaType)mediaTypeForNativeMediaType:(cricket::MediaType)nativeMediaType;
+
++ (cricket::MediaType)nativeMediaTypeForMediaType:(RTCRtpMediaType)mediaType;
+
++ (NSString*)stringForMediaType:(RTCRtpMediaType)mediaType;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpReceiver.h b/sdk/objc/api/peerconnection/RTCRtpReceiver.h
new file mode 100644
index 0000000..9023479
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpReceiver.h
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 2016 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"
+#import "RTCMediaStreamTrack.h"
+#import "RTCRtpParameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Represents the media type of the RtpReceiver. */
+typedef NS_ENUM(NSInteger, RTCRtpMediaType) {
+  RTCRtpMediaTypeAudio,
+  RTCRtpMediaTypeVideo,
+  RTCRtpMediaTypeData,
+};
+
+@class RTCRtpReceiver;
+
+RTC_EXPORT
+@protocol RTCRtpReceiverDelegate <NSObject>
+
+/** Called when the first RTP packet is received.
+ *
+ *  Note: Currently if there are multiple RtpReceivers of the same media type,
+ *  they will all call OnFirstPacketReceived at once.
+ *
+ *  For example, if we create three audio receivers, A/B/C, they will listen to
+ *  the same signal from the underneath network layer. Whenever the first audio packet
+ *  is received, the underneath signal will be fired. All the receivers A/B/C will be
+ *  notified and the callback of the receiver's delegate will be called.
+ *
+ *  The process is the same for video receivers.
+ */
+- (void)rtpReceiver:(RTCRtpReceiver *)rtpReceiver
+    didReceiveFirstPacketForMediaType:(RTCRtpMediaType)mediaType;
+
+@end
+
+RTC_EXPORT
+@protocol RTCRtpReceiver <NSObject>
+
+/** A unique identifier for this receiver. */
+@property(nonatomic, readonly) NSString *receiverId;
+
+/** The currently active RTCRtpParameters, as defined in
+ *  https://www.w3.org/TR/webrtc/#idl-def-RTCRtpParameters.
+ *
+ *  The WebRTC specification only defines RTCRtpParameters in terms of senders,
+ *  but this API also applies them to receivers, similar to ORTC:
+ *  http://ortc.org/wp-content/uploads/2016/03/ortc.html#rtcrtpparameters*.
+ */
+@property(nonatomic, readonly) RTCRtpParameters *parameters;
+
+/** The RTCMediaStreamTrack associated with the receiver.
+ *  Note: reading this property returns a new instance of
+ *  RTCMediaStreamTrack. Use isEqual: instead of == to compare
+ *  RTCMediaStreamTrack instances.
+ */
+@property(nonatomic, readonly, nullable) RTCMediaStreamTrack *track;
+
+/** The delegate for this RtpReceiver. */
+@property(nonatomic, weak) id<RTCRtpReceiverDelegate> delegate;
+
+@end
+
+RTC_EXPORT
+@interface RTCRtpReceiver : NSObject <RTCRtpReceiver>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpReceiver.mm b/sdk/objc/api/peerconnection/RTCRtpReceiver.mm
new file mode 100644
index 0000000..6d2048d
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpReceiver.mm
@@ -0,0 +1,154 @@
+/*
+ *  Copyright 2016 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 "RTCRtpReceiver+Private.h"
+
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCRtpParameters+Private.h"
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include "api/mediastreaminterface.h"
+
+namespace webrtc {
+
+RtpReceiverDelegateAdapter::RtpReceiverDelegateAdapter(
+    RTCRtpReceiver *receiver) {
+  RTC_CHECK(receiver);
+  receiver_ = receiver;
+}
+
+void RtpReceiverDelegateAdapter::OnFirstPacketReceived(
+    cricket::MediaType media_type) {
+  RTCRtpMediaType packet_media_type =
+      [RTCRtpReceiver mediaTypeForNativeMediaType:media_type];
+  RTCRtpReceiver *receiver = receiver_;
+  [receiver.delegate rtpReceiver:receiver didReceiveFirstPacketForMediaType:packet_media_type];
+}
+
+}  // namespace webrtc
+
+@implementation RTCRtpReceiver {
+  RTCPeerConnectionFactory *_factory;
+  rtc::scoped_refptr<webrtc::RtpReceiverInterface> _nativeRtpReceiver;
+  std::unique_ptr<webrtc::RtpReceiverDelegateAdapter> _observer;
+}
+
+@synthesize delegate = _delegate;
+
+- (NSString *)receiverId {
+  return [NSString stringForStdString:_nativeRtpReceiver->id()];
+}
+
+- (RTCRtpParameters *)parameters {
+  return [[RTCRtpParameters alloc]
+      initWithNativeParameters:_nativeRtpReceiver->GetParameters()];
+}
+
+- (void)setParameters:(RTCRtpParameters *)parameters {
+  if (!_nativeRtpReceiver->SetParameters(parameters.nativeParameters)) {
+    RTCLogError(@"RTCRtpReceiver(%p): Failed to set parameters: %@", self,
+        parameters);
+  }
+}
+
+- (nullable RTCMediaStreamTrack *)track {
+  rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack(
+    _nativeRtpReceiver->track());
+  if (nativeTrack) {
+    return [RTCMediaStreamTrack mediaTrackForNativeTrack:nativeTrack factory:_factory];
+  }
+  return nil;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCRtpReceiver {\n  receiverId: %@\n}",
+      self.receiverId];
+}
+
+- (void)dealloc {
+  if (_nativeRtpReceiver) {
+    _nativeRtpReceiver->SetObserver(nullptr);
+  }
+}
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) {
+    return YES;
+  }
+  if (object == nil) {
+    return NO;
+  }
+  if (![object isMemberOfClass:[self class]]) {
+    return NO;
+  }
+  RTCRtpReceiver *receiver = (RTCRtpReceiver *)object;
+  return _nativeRtpReceiver == receiver.nativeRtpReceiver;
+}
+
+- (NSUInteger)hash {
+  return (NSUInteger)_nativeRtpReceiver.get();
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::RtpReceiverInterface>)nativeRtpReceiver {
+  return _nativeRtpReceiver;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeRtpReceiver:
+                  (rtc::scoped_refptr<webrtc::RtpReceiverInterface>)nativeRtpReceiver {
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeRtpReceiver = nativeRtpReceiver;
+    RTCLogInfo(
+        @"RTCRtpReceiver(%p): created receiver: %@", self, self.description);
+    _observer.reset(new webrtc::RtpReceiverDelegateAdapter(self));
+    _nativeRtpReceiver->SetObserver(_observer.get());
+  }
+  return self;
+}
+
++ (RTCRtpMediaType)mediaTypeForNativeMediaType:
+    (cricket::MediaType)nativeMediaType {
+  switch (nativeMediaType) {
+    case cricket::MEDIA_TYPE_AUDIO:
+      return RTCRtpMediaTypeAudio;
+    case cricket::MEDIA_TYPE_VIDEO:
+      return RTCRtpMediaTypeVideo;
+    case cricket::MEDIA_TYPE_DATA:
+      return RTCRtpMediaTypeData;
+  }
+}
+
++ (cricket::MediaType)nativeMediaTypeForMediaType:(RTCRtpMediaType)mediaType {
+  switch (mediaType) {
+    case RTCRtpMediaTypeAudio:
+      return cricket::MEDIA_TYPE_AUDIO;
+    case RTCRtpMediaTypeVideo:
+      return cricket::MEDIA_TYPE_VIDEO;
+    case RTCRtpMediaTypeData:
+      return cricket::MEDIA_TYPE_DATA;
+  }
+}
+
++ (NSString *)stringForMediaType:(RTCRtpMediaType)mediaType {
+  switch (mediaType) {
+    case RTCRtpMediaTypeAudio:
+      return @"AUDIO";
+    case RTCRtpMediaTypeVideo:
+      return @"VIDEO";
+    case RTCRtpMediaTypeData:
+      return @"DATA";
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpSender+Private.h b/sdk/objc/api/peerconnection/RTCRtpSender+Private.h
new file mode 100644
index 0000000..d0dcb2b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpSender+Private.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2016 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 "RTCRtpSender.h"
+
+#include "api/rtpsenderinterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+@interface RTCRtpSender ()
+
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::RtpSenderInterface> nativeRtpSender;
+
+/** Initialize an RTCRtpSender with a native RtpSenderInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
+                nativeRtpSender:(rtc::scoped_refptr<webrtc::RtpSenderInterface>)nativeRtpSender
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpSender.h b/sdk/objc/api/peerconnection/RTCRtpSender.h
new file mode 100644
index 0000000..55ab383
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpSender.h
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2016 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 "RTCDtmfSender.h"
+#import "RTCMacros.h"
+#import "RTCMediaStreamTrack.h"
+#import "RTCRtpParameters.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@protocol RTCRtpSender <NSObject>
+
+/** A unique identifier for this sender. */
+@property(nonatomic, readonly) NSString *senderId;
+
+/** The currently active RTCRtpParameters, as defined in
+ *  https://www.w3.org/TR/webrtc/#idl-def-RTCRtpParameters.
+ */
+@property(nonatomic, copy) RTCRtpParameters *parameters;
+
+/** The RTCMediaStreamTrack associated with the sender.
+ *  Note: reading this property returns a new instance of
+ *  RTCMediaStreamTrack. Use isEqual: instead of == to compare
+ *  RTCMediaStreamTrack instances.
+ */
+@property(nonatomic, copy, nullable) RTCMediaStreamTrack *track;
+
+/** The RTCDtmfSender accociated with the RTP sender. */
+@property(nonatomic, readonly, nullable) id<RTCDtmfSender> dtmfSender;
+
+@end
+
+RTC_EXPORT
+@interface RTCRtpSender : NSObject <RTCRtpSender>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpSender.mm b/sdk/objc/api/peerconnection/RTCRtpSender.mm
new file mode 100644
index 0000000..64e9204
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpSender.mm
@@ -0,0 +1,105 @@
+/*
+ *  Copyright 2016 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 "RTCRtpSender+Private.h"
+
+#import "RTCDtmfSender+Private.h"
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCRtpParameters+Private.h"
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include "api/mediastreaminterface.h"
+
+@implementation RTCRtpSender {
+  RTCPeerConnectionFactory *_factory;
+  rtc::scoped_refptr<webrtc::RtpSenderInterface> _nativeRtpSender;
+}
+
+@synthesize dtmfSender = _dtmfSender;
+
+- (NSString *)senderId {
+  return [NSString stringForStdString:_nativeRtpSender->id()];
+}
+
+- (RTCRtpParameters *)parameters {
+  return [[RTCRtpParameters alloc]
+      initWithNativeParameters:_nativeRtpSender->GetParameters()];
+}
+
+- (void)setParameters:(RTCRtpParameters *)parameters {
+  if (!_nativeRtpSender->SetParameters(parameters.nativeParameters).ok()) {
+    RTCLogError(@"RTCRtpSender(%p): Failed to set parameters: %@", self,
+        parameters);
+  }
+}
+
+- (RTCMediaStreamTrack *)track {
+  rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack(
+    _nativeRtpSender->track());
+  if (nativeTrack) {
+    return [RTCMediaStreamTrack mediaTrackForNativeTrack:nativeTrack factory:_factory];
+  }
+  return nil;
+}
+
+- (void)setTrack:(RTCMediaStreamTrack *)track {
+  if (!_nativeRtpSender->SetTrack(track.nativeTrack)) {
+    RTCLogError(@"RTCRtpSender(%p): Failed to set track %@", self, track);
+  }
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCRtpSender {\n  senderId: %@\n}",
+      self.senderId];
+}
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) {
+    return YES;
+  }
+  if (object == nil) {
+    return NO;
+  }
+  if (![object isMemberOfClass:[self class]]) {
+    return NO;
+  }
+  RTCRtpSender *sender = (RTCRtpSender *)object;
+  return _nativeRtpSender == sender.nativeRtpSender;
+}
+
+- (NSUInteger)hash {
+  return (NSUInteger)_nativeRtpSender.get();
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::RtpSenderInterface>)nativeRtpSender {
+  return _nativeRtpSender;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                nativeRtpSender:(rtc::scoped_refptr<webrtc::RtpSenderInterface>)nativeRtpSender {
+  NSParameterAssert(factory);
+  NSParameterAssert(nativeRtpSender);
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeRtpSender = nativeRtpSender;
+    rtc::scoped_refptr<webrtc::DtmfSenderInterface> nativeDtmfSender(
+        _nativeRtpSender->GetDtmfSender());
+    if (nativeDtmfSender) {
+      _dtmfSender = [[RTCDtmfSender alloc] initWithNativeDtmfSender:nativeDtmfSender];
+    }
+    RTCLogInfo(@"RTCRtpSender(%p): created sender: %@", self, self.description);
+  }
+  return self;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCRtpTransceiver+Private.h b/sdk/objc/api/peerconnection/RTCRtpTransceiver+Private.h
new file mode 100644
index 0000000..61cbcb3
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpTransceiver+Private.h
@@ -0,0 +1,44 @@
+/*
+ *  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 "RTCRtpTransceiver.h"
+
+#include "api/rtptransceiverinterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class RTCPeerConnectionFactory;
+
+@interface RTCRtpTransceiverInit ()
+
+@property(nonatomic, readonly) webrtc::RtpTransceiverInit nativeInit;
+
+@end
+
+@interface RTCRtpTransceiver ()
+
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::RtpTransceiverInterface>
+    nativeRtpTransceiver;
+
+/** Initialize an RTCRtpTransceiver with a native RtpTransceiverInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
+           nativeRtpTransceiver:
+               (rtc::scoped_refptr<webrtc::RtpTransceiverInterface>)nativeRtpTransceiver
+    NS_DESIGNATED_INITIALIZER;
+
++ (webrtc::RtpTransceiverDirection)nativeRtpTransceiverDirectionFromDirection:
+        (RTCRtpTransceiverDirection)direction;
+
++ (RTCRtpTransceiverDirection)rtpTransceiverDirectionFromNativeDirection:
+        (webrtc::RtpTransceiverDirection)nativeDirection;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpTransceiver.h b/sdk/objc/api/peerconnection/RTCRtpTransceiver.h
new file mode 100644
index 0000000..402b04e
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpTransceiver.h
@@ -0,0 +1,128 @@
+/*
+ *  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"
+#import "RTCRtpReceiver.h"
+#import "RTCRtpSender.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection */
+typedef NS_ENUM(NSInteger, RTCRtpTransceiverDirection) {
+  RTCRtpTransceiverDirectionSendRecv,
+  RTCRtpTransceiverDirectionSendOnly,
+  RTCRtpTransceiverDirectionRecvOnly,
+  RTCRtpTransceiverDirectionInactive,
+};
+
+/** Structure for initializing an RTCRtpTransceiver in a call to
+ *  RTCPeerConnection.addTransceiver.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
+ */
+@interface RTCRtpTransceiverInit : NSObject
+
+/** Direction of the RTCRtpTransceiver. See RTCRtpTransceiver.direction. */
+@property(nonatomic) RTCRtpTransceiverDirection direction;
+
+/** The added RTCRtpTransceiver will be added to these streams. */
+@property(nonatomic) NSArray<NSString *> *streamIds;
+
+/** TODO(bugs.webrtc.org/7600): Not implemented. */
+@property(nonatomic) NSArray<RTCRtpEncodingParameters *> *sendEncodings;
+
+@end
+
+@class RTCRtpTransceiver;
+
+/** The RTCRtpTransceiver maps to the RTCRtpTransceiver defined by the WebRTC
+ *  specification. A transceiver represents a combination of an RTCRtpSender
+ *  and an RTCRtpReceiver that share a common mid. As defined in JSEP, an
+ *  RTCRtpTransceiver is said to be associated with a media description if its
+ *  mid property is non-nil; otherwise, it is said to be disassociated.
+ *  JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24
+ *
+ *  Note that RTCRtpTransceivers are only supported when using
+ *  RTCPeerConnection with Unified Plan SDP.
+ *
+ *  WebRTC specification for RTCRtpTransceiver, the JavaScript analog:
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver
+ */
+RTC_EXPORT
+@protocol RTCRtpTransceiver <NSObject>
+
+/** Media type of the transceiver. The sender and receiver will also have this
+ *  type.
+ */
+@property(nonatomic, readonly) RTCRtpMediaType mediaType;
+
+/** The mid attribute is the mid negotiated and present in the local and
+ *  remote descriptions. Before negotiation is complete, the mid value may be
+ *  nil. After rollbacks, the value may change from a non-nil value to nil.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
+ */
+@property(nonatomic, readonly) NSString *mid;
+
+/** The sender attribute exposes the RTCRtpSender corresponding to the RTP
+ *  media that may be sent with the transceiver's mid. The sender is always
+ *  present, regardless of the direction of media.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender
+ */
+@property(nonatomic, readonly) RTCRtpSender *sender;
+
+/** The receiver attribute exposes the RTCRtpReceiver corresponding to the RTP
+ *  media that may be received with the transceiver's mid. The receiver is
+ *  always present, regardless of the direction of media.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver
+ */
+@property(nonatomic, readonly) RTCRtpReceiver *receiver;
+
+/** The isStopped attribute indicates that the sender of this transceiver will
+ *  no longer send, and that the receiver will no longer receive. It is true if
+ *  either stop has been called or if setting the local or remote description
+ *  has caused the RTCRtpTransceiver to be stopped.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped
+ */
+@property(nonatomic, readonly) BOOL isStopped;
+
+/** The direction attribute indicates the preferred direction of this
+ *  transceiver, which will be used in calls to createOffer and createAnswer.
+ *  An update of directionality does not take effect immediately. Instead,
+ *  future calls to createOffer and createAnswer mark the corresponding media
+ *  descriptions as sendrecv, sendonly, recvonly, or inactive.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
+ */
+@property(nonatomic) RTCRtpTransceiverDirection direction;
+
+/** The currentDirection attribute indicates the current direction negotiated
+ *  for this transceiver. If this transceiver has never been represented in an
+ *  offer/answer exchange, or if the transceiver is stopped, the value is not
+ *  present and this method returns NO.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
+ */
+- (BOOL)currentDirection:(RTCRtpTransceiverDirection *)currentDirectionOut;
+
+/** The stop method irreversibly stops the RTCRtpTransceiver. The sender of
+ *  this transceiver will no longer send, the receiver will no longer receive.
+ *  https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop
+ */
+- (void)stop;
+
+@end
+
+RTC_EXPORT
+@interface RTCRtpTransceiver : NSObject <RTCRtpTransceiver>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm b/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm
new file mode 100644
index 0000000..fe1ebb5
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCRtpTransceiver.mm
@@ -0,0 +1,169 @@
+/*
+ *  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 "RTCRtpTransceiver+Private.h"
+
+#import "RTCRtpEncodingParameters+Private.h"
+#import "RTCRtpParameters+Private.h"
+#import "RTCRtpReceiver+Private.h"
+#import "RTCRtpSender+Private.h"
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCRtpTransceiverInit
+
+@synthesize direction = _direction;
+@synthesize streamIds = _streamIds;
+@synthesize sendEncodings = _sendEncodings;
+
+- (instancetype)init {
+  if (self = [super init]) {
+    _direction = RTCRtpTransceiverDirectionSendRecv;
+  }
+  return self;
+}
+
+- (webrtc::RtpTransceiverInit)nativeInit {
+  webrtc::RtpTransceiverInit init;
+  init.direction = [RTCRtpTransceiver nativeRtpTransceiverDirectionFromDirection:_direction];
+  for (NSString *streamId in _streamIds) {
+    init.stream_ids.push_back([streamId UTF8String]);
+  }
+  for (RTCRtpEncodingParameters *sendEncoding in _sendEncodings) {
+    init.send_encodings.push_back(sendEncoding.nativeParameters);
+  }
+  return init;
+}
+
+@end
+
+@implementation RTCRtpTransceiver {
+  RTCPeerConnectionFactory *_factory;
+  rtc::scoped_refptr<webrtc::RtpTransceiverInterface> _nativeRtpTransceiver;
+}
+
+- (RTCRtpMediaType)mediaType {
+  return [RTCRtpReceiver mediaTypeForNativeMediaType:_nativeRtpTransceiver->media_type()];
+}
+
+- (NSString *)mid {
+  if (_nativeRtpTransceiver->mid()) {
+    return [NSString stringForStdString:*_nativeRtpTransceiver->mid()];
+  } else {
+    return nil;
+  }
+}
+
+@synthesize sender = _sender;
+@synthesize receiver = _receiver;
+
+- (BOOL)isStopped {
+  return _nativeRtpTransceiver->stopped();
+}
+
+- (RTCRtpTransceiverDirection)direction {
+  return [RTCRtpTransceiver
+      rtpTransceiverDirectionFromNativeDirection:_nativeRtpTransceiver->direction()];
+}
+
+- (void)setDirection:(RTCRtpTransceiverDirection)direction {
+  _nativeRtpTransceiver->SetDirection(
+      [RTCRtpTransceiver nativeRtpTransceiverDirectionFromDirection:direction]);
+}
+
+- (BOOL)currentDirection:(RTCRtpTransceiverDirection *)currentDirectionOut {
+  if (_nativeRtpTransceiver->current_direction()) {
+    *currentDirectionOut = [RTCRtpTransceiver
+        rtpTransceiverDirectionFromNativeDirection:*_nativeRtpTransceiver->current_direction()];
+    return YES;
+  } else {
+    return NO;
+  }
+}
+
+- (void)stop {
+  _nativeRtpTransceiver->Stop();
+}
+
+- (NSString *)description {
+  return [NSString
+      stringWithFormat:@"RTCRtpTransceiver {\n  sender: %@\n  receiver: %@\n}", _sender, _receiver];
+}
+
+- (BOOL)isEqual:(id)object {
+  if (self == object) {
+    return YES;
+  }
+  if (object == nil) {
+    return NO;
+  }
+  if (![object isMemberOfClass:[self class]]) {
+    return NO;
+  }
+  RTCRtpTransceiver *transceiver = (RTCRtpTransceiver *)object;
+  return _nativeRtpTransceiver == transceiver.nativeRtpTransceiver;
+}
+
+- (NSUInteger)hash {
+  return (NSUInteger)_nativeRtpTransceiver.get();
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::RtpTransceiverInterface>)nativeRtpTransceiver {
+  return _nativeRtpTransceiver;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+           nativeRtpTransceiver:
+               (rtc::scoped_refptr<webrtc::RtpTransceiverInterface>)nativeRtpTransceiver {
+  NSParameterAssert(factory);
+  NSParameterAssert(nativeRtpTransceiver);
+  if (self = [super init]) {
+    _factory = factory;
+    _nativeRtpTransceiver = nativeRtpTransceiver;
+    _sender = [[RTCRtpSender alloc] initWithFactory:_factory
+                                    nativeRtpSender:nativeRtpTransceiver->sender()];
+    _receiver = [[RTCRtpReceiver alloc] initWithFactory:_factory
+                                      nativeRtpReceiver:nativeRtpTransceiver->receiver()];
+    RTCLogInfo(@"RTCRtpTransceiver(%p): created transceiver: %@", self, self.description);
+  }
+  return self;
+}
+
++ (webrtc::RtpTransceiverDirection)nativeRtpTransceiverDirectionFromDirection:
+        (RTCRtpTransceiverDirection)direction {
+  switch (direction) {
+    case RTCRtpTransceiverDirectionSendRecv:
+      return webrtc::RtpTransceiverDirection::kSendRecv;
+    case RTCRtpTransceiverDirectionSendOnly:
+      return webrtc::RtpTransceiverDirection::kSendOnly;
+    case RTCRtpTransceiverDirectionRecvOnly:
+      return webrtc::RtpTransceiverDirection::kRecvOnly;
+    case RTCRtpTransceiverDirectionInactive:
+      return webrtc::RtpTransceiverDirection::kInactive;
+  }
+}
+
++ (RTCRtpTransceiverDirection)rtpTransceiverDirectionFromNativeDirection:
+        (webrtc::RtpTransceiverDirection)nativeDirection {
+  switch (nativeDirection) {
+    case webrtc::RtpTransceiverDirection::kSendRecv:
+      return RTCRtpTransceiverDirectionSendRecv;
+    case webrtc::RtpTransceiverDirection::kSendOnly:
+      return RTCRtpTransceiverDirectionSendOnly;
+    case webrtc::RtpTransceiverDirection::kRecvOnly:
+      return RTCRtpTransceiverDirectionRecvOnly;
+    case webrtc::RtpTransceiverDirection::kInactive:
+      return RTCRtpTransceiverDirectionInactive;
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCSSLAdapter.h b/sdk/objc/api/peerconnection/RTCSSLAdapter.h
new file mode 100644
index 0000000..f68bc5e
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCSSLAdapter.h
@@ -0,0 +1,20 @@
+/*
+ *  Copyright 2016 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"
+
+/**
+ * Initialize and clean up the SSL library. Failure is fatal. These call the
+ * corresponding functions in webrtc/rtc_base/ssladapter.h.
+ */
+RTC_EXTERN BOOL RTCInitializeSSL(void);
+RTC_EXTERN BOOL RTCCleanupSSL(void);
diff --git a/sdk/objc/api/peerconnection/RTCSSLAdapter.mm b/sdk/objc/api/peerconnection/RTCSSLAdapter.mm
new file mode 100644
index 0000000..18388f9
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCSSLAdapter.mm
@@ -0,0 +1,26 @@
+/*
+ *  Copyright 2016 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 "RTCSSLAdapter.h"
+
+#include "rtc_base/checks.h"
+#include "rtc_base/ssladapter.h"
+
+BOOL RTCInitializeSSL(void) {
+  BOOL initialized = rtc::InitializeSSL();
+  RTC_DCHECK(initialized);
+  return initialized;
+}
+
+BOOL RTCCleanupSSL(void) {
+  BOOL cleanedUp = rtc::CleanupSSL();
+  RTC_DCHECK(cleanedUp);
+  return cleanedUp;
+}
diff --git a/sdk/objc/api/peerconnection/RTCSessionDescription+Private.h b/sdk/objc/api/peerconnection/RTCSessionDescription+Private.h
new file mode 100644
index 0000000..cc255cd
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCSessionDescription+Private.h
@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2015 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 "RTCSessionDescription.h"
+
+#include "api/jsep.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCSessionDescription ()
+
+/**
+ * The native SessionDescriptionInterface representation of this
+ * RTCSessionDescription object. This is needed to pass to the underlying C++
+ * APIs.
+ */
+@property(nonatomic, readonly, nullable) webrtc::SessionDescriptionInterface *nativeDescription;
+
+/**
+ * Initialize an RTCSessionDescription from a native
+ * SessionDescriptionInterface. No ownership is taken of the native session
+ * description.
+ */
+- (instancetype)initWithNativeDescription:
+        (const webrtc::SessionDescriptionInterface *)nativeDescription;
+
++ (std::string)stdStringForType:(RTCSdpType)type;
+
++ (RTCSdpType)typeForStdString:(const std::string &)string;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCSessionDescription.h b/sdk/objc/api/peerconnection/RTCSessionDescription.h
new file mode 100644
index 0000000..bef3a4c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCSessionDescription.h
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 2015 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"
+
+/**
+ * Represents the session description type. This exposes the same types that are
+ * in C++, which doesn't include the rollback type that is in the W3C spec.
+ */
+typedef NS_ENUM(NSInteger, RTCSdpType) {
+  RTCSdpTypeOffer,
+  RTCSdpTypePrAnswer,
+  RTCSdpTypeAnswer,
+};
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+@interface RTCSessionDescription : NSObject
+
+/** The type of session description. */
+@property(nonatomic, readonly) RTCSdpType type;
+
+/** The SDP string representation of this session description. */
+@property(nonatomic, readonly) NSString *sdp;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Initialize a session description with a type and SDP string. */
+- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp NS_DESIGNATED_INITIALIZER;
+
++ (NSString *)stringForType:(RTCSdpType)type;
+
++ (RTCSdpType)typeForString:(NSString *)string;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCSessionDescription.mm b/sdk/objc/api/peerconnection/RTCSessionDescription.mm
new file mode 100644
index 0000000..21e5e42
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCSessionDescription.mm
@@ -0,0 +1,102 @@
+/*
+ *  Copyright 2015 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 "RTCSessionDescription+Private.h"
+
+#import "base/RTCLogging.h"
+#import "helpers/NSString+StdString.h"
+
+#include "rtc_base/checks.h"
+
+@implementation RTCSessionDescription
+
+@synthesize type = _type;
+@synthesize sdp = _sdp;
+
++ (NSString *)stringForType:(RTCSdpType)type {
+  std::string string = [[self class] stdStringForType:type];
+  return [NSString stringForStdString:string];
+}
+
++ (RTCSdpType)typeForString:(NSString *)string {
+  std::string typeString = string.stdString;
+  return [[self class] typeForStdString:typeString];
+}
+
+- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp {
+  NSParameterAssert(sdp.length);
+  if (self = [super init]) {
+    _type = type;
+    _sdp = [sdp copy];
+  }
+  return self;
+}
+
+- (NSString *)description {
+  return [NSString stringWithFormat:@"RTCSessionDescription:\n%@\n%@",
+                                    [[self class] stringForType:_type],
+                                    _sdp];
+}
+
+#pragma mark - Private
+
+- (webrtc::SessionDescriptionInterface *)nativeDescription {
+  webrtc::SdpParseError error;
+
+  webrtc::SessionDescriptionInterface *description =
+      webrtc::CreateSessionDescription([[self class] stdStringForType:_type],
+                                       _sdp.stdString,
+                                       &error);
+
+  if (!description) {
+    RTCLogError(@"Failed to create session description: %s\nline: %s",
+                error.description.c_str(),
+                error.line.c_str());
+  }
+
+  return description;
+}
+
+- (instancetype)initWithNativeDescription:
+    (const webrtc::SessionDescriptionInterface *)nativeDescription {
+  NSParameterAssert(nativeDescription);
+  std::string sdp;
+  nativeDescription->ToString(&sdp);
+  RTCSdpType type = [[self class] typeForStdString:nativeDescription->type()];
+
+  return [self initWithType:type
+                        sdp:[NSString stringForStdString:sdp]];
+}
+
++ (std::string)stdStringForType:(RTCSdpType)type {
+  switch (type) {
+    case RTCSdpTypeOffer:
+      return webrtc::SessionDescriptionInterface::kOffer;
+    case RTCSdpTypePrAnswer:
+      return webrtc::SessionDescriptionInterface::kPrAnswer;
+    case RTCSdpTypeAnswer:
+      return webrtc::SessionDescriptionInterface::kAnswer;
+  }
+}
+
++ (RTCSdpType)typeForStdString:(const std::string &)string {
+  if (string == webrtc::SessionDescriptionInterface::kOffer) {
+    return RTCSdpTypeOffer;
+  } else if (string == webrtc::SessionDescriptionInterface::kPrAnswer) {
+    return RTCSdpTypePrAnswer;
+  } else if (string == webrtc::SessionDescriptionInterface::kAnswer) {
+    return RTCSdpTypeAnswer;
+  } else {
+    RTC_NOTREACHED();
+    return RTCSdpTypeOffer;
+  }
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCTracing.h b/sdk/objc/api/peerconnection/RTCTracing.h
new file mode 100644
index 0000000..5c66e5a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCTracing.h
@@ -0,0 +1,21 @@
+/*
+ *  Copyright 2016 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"
+
+RTC_EXTERN void RTCSetupInternalTracer(void);
+/** Starts capture to specified file. Must be a valid writable path.
+ *  Returns YES if capture starts.
+ */
+RTC_EXTERN BOOL RTCStartInternalCapture(NSString* filePath);
+RTC_EXTERN void RTCStopInternalCapture(void);
+RTC_EXTERN void RTCShutdownInternalTracer(void);
diff --git a/sdk/objc/api/peerconnection/RTCTracing.mm b/sdk/objc/api/peerconnection/RTCTracing.mm
new file mode 100644
index 0000000..72f9f4d
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCTracing.mm
@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2016 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 "RTCTracing.h"
+
+#include "rtc_base/event_tracer.h"
+
+void RTCSetupInternalTracer(void) {
+  rtc::tracing::SetupInternalTracer();
+}
+
+BOOL RTCStartInternalCapture(NSString *filePath) {
+  return rtc::tracing::StartInternalCapture(filePath.UTF8String);
+}
+
+void RTCStopInternalCapture(void) {
+  rtc::tracing::StopInternalCapture();
+}
+
+void RTCShutdownInternalTracer(void) {
+  rtc::tracing::ShutdownInternalTracer();
+}
diff --git a/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.h b/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.h
new file mode 100644
index 0000000..9c2178f
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "base/RTCVideoCodecInfo.h"
+
+#include "api/video_codecs/sdp_video_format.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/* Interface for converting to/from internal C++ formats. */
+@interface RTCVideoCodecInfo (Private)
+
+- (instancetype)initWithNativeSdpVideoFormat:(webrtc::SdpVideoFormat)format;
+- (webrtc::SdpVideoFormat)nativeSdpVideoFormat;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.mm b/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.mm
new file mode 100644
index 0000000..21aacf6
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoCodecInfo+Private.mm
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCVideoCodecInfo+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCVideoCodecInfo (Private)
+
+- (instancetype)initWithNativeSdpVideoFormat:(webrtc::SdpVideoFormat)format {
+  NSMutableDictionary *params = [NSMutableDictionary dictionary];
+  for (auto it = format.parameters.begin(); it != format.parameters.end(); ++it) {
+    [params setObject:[NSString stringForStdString:it->second]
+               forKey:[NSString stringForStdString:it->first]];
+  }
+  return [self initWithName:[NSString stringForStdString:format.name] parameters:params];
+}
+
+- (webrtc::SdpVideoFormat)nativeSdpVideoFormat {
+  std::map<std::string, std::string> parameters;
+  for (NSString *paramKey in self.parameters.allKeys) {
+    std::string key = [NSString stdStringForString:paramKey];
+    std::string value = [NSString stdStringForString:self.parameters[paramKey]];
+    parameters[key] = value;
+  }
+
+  return webrtc::SdpVideoFormat([NSString stdStringForString:self.name], parameters);
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.h b/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.h
new file mode 100644
index 0000000..5b06245
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "base/RTCVideoEncoderSettings.h"
+
+#include "modules/video_coding/include/video_codec_interface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/* Interfaces for converting to/from internal C++ formats. */
+@interface RTCVideoEncoderSettings (Private)
+
+- (instancetype)initWithNativeVideoCodec:(const webrtc::VideoCodec *__nullable)videoCodec;
+- (webrtc::VideoCodec)nativeVideoCodec;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.mm b/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.mm
new file mode 100644
index 0000000..6fb81db
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoEncoderSettings+Private.mm
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCVideoEncoderSettings+Private.h"
+
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCVideoEncoderSettings (Private)
+
+- (instancetype)initWithNativeVideoCodec:(const webrtc::VideoCodec *)videoCodec {
+  if (self = [super init]) {
+    if (videoCodec) {
+      const char *codecName = CodecTypeToPayloadString(videoCodec->codecType);
+      self.name = [NSString stringWithUTF8String:codecName];
+
+      self.width = videoCodec->width;
+      self.height = videoCodec->height;
+      self.startBitrate = videoCodec->startBitrate;
+      self.maxBitrate = videoCodec->maxBitrate;
+      self.minBitrate = videoCodec->minBitrate;
+      self.targetBitrate = videoCodec->targetBitrate;
+      self.maxFramerate = videoCodec->maxFramerate;
+      self.qpMax = videoCodec->qpMax;
+      self.mode = (RTCVideoCodecMode)videoCodec->mode;
+    }
+  }
+
+  return self;
+}
+
+- (webrtc::VideoCodec)nativeVideoCodec {
+  webrtc::VideoCodec videoCodec;
+  videoCodec.width = self.width;
+  videoCodec.height = self.height;
+  videoCodec.startBitrate = self.startBitrate;
+  videoCodec.maxBitrate = self.maxBitrate;
+  videoCodec.minBitrate = self.minBitrate;
+  videoCodec.targetBitrate = self.targetBitrate;
+  videoCodec.maxBitrate = self.maxBitrate;
+  videoCodec.qpMax = self.qpMax;
+  videoCodec.mode = (webrtc::VideoCodecMode)self.mode;
+
+  return videoCodec;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCVideoSource+Private.h b/sdk/objc/api/peerconnection/RTCVideoSource+Private.h
new file mode 100644
index 0000000..2441e0c
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoSource+Private.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 2015 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 "RTCVideoSource.h"
+
+#import "RTCMediaSource+Private.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCVideoSource ()
+
+/**
+ * The VideoTrackSourceInterface object passed to this RTCVideoSource during
+ * construction.
+ */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::VideoTrackSourceInterface>
+    nativeVideoSource;
+
+/** Initialize an RTCVideoSource from a native VideoTrackSourceInterface. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeVideoSource:
+                  (rtc::scoped_refptr<webrtc::VideoTrackSourceInterface>)nativeVideoSource
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type NS_UNAVAILABLE;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                signalingThread:(rtc::Thread *)signalingThread
+                   workerThread:(rtc::Thread *)workerThread;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoSource.h b/sdk/objc/api/peerconnection/RTCVideoSource.h
new file mode 100644
index 0000000..1ead394
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoSource.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2015 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"
+#import "RTCMediaSource.h"
+#import "RTCVideoCapturer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+RTC_EXPORT
+
+@interface RTCVideoSource : RTCMediaSource <RTCVideoCapturerDelegate>
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Calling this function will cause frames to be scaled down to the
+ * requested resolution. Also, frames will be cropped to match the
+ * requested aspect ratio, and frames will be dropped to match the
+ * requested fps. The requested aspect ratio is orientation agnostic and
+ * will be adjusted to maintain the input orientation, so it doesn't
+ * matter if e.g. 1280x720 or 720x1280 is requested.
+ */
+- (void)adaptOutputFormatToWidth:(int)width height:(int)height fps:(int)fps;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoSource.mm b/sdk/objc/api/peerconnection/RTCVideoSource.mm
new file mode 100644
index 0000000..1cbeb0b
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoSource.mm
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2015 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 "RTCVideoSource+Private.h"
+
+#include "api/videosourceproxy.h"
+#include "rtc_base/checks.h"
+#include "sdk/objc/native/src/objc_video_track_source.h"
+
+static webrtc::ObjCVideoTrackSource *getObjCVideoSource(
+    const rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> nativeSource) {
+  webrtc::VideoTrackSourceProxy *proxy_source =
+      static_cast<webrtc::VideoTrackSourceProxy *>(nativeSource.get());
+  return static_cast<webrtc::ObjCVideoTrackSource *>(proxy_source->internal());
+}
+
+// TODO(magjed): Refactor this class and target ObjCVideoTrackSource only once
+// RTCAVFoundationVideoSource is gone. See http://crbug/webrtc/7177 for more
+// info.
+@implementation RTCVideoSource {
+  rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> _nativeVideoSource;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeVideoSource:
+                  (rtc::scoped_refptr<webrtc::VideoTrackSourceInterface>)nativeVideoSource {
+  RTC_DCHECK(factory);
+  RTC_DCHECK(nativeVideoSource);
+  if (self = [super initWithFactory:factory
+                  nativeMediaSource:nativeVideoSource
+                               type:RTCMediaSourceTypeVideo]) {
+    _nativeVideoSource = nativeVideoSource;
+  }
+  return self;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+              nativeMediaSource:(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
+                           type:(RTCMediaSourceType)type {
+  RTC_NOTREACHED();
+  return nil;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                signalingThread:(rtc::Thread *)signalingThread
+                   workerThread:(rtc::Thread *)workerThread {
+  rtc::scoped_refptr<webrtc::ObjCVideoTrackSource> objCVideoTrackSource(
+      new rtc::RefCountedObject<webrtc::ObjCVideoTrackSource>());
+
+  return [self initWithFactory:factory
+             nativeVideoSource:webrtc::VideoTrackSourceProxy::Create(
+                                   signalingThread, workerThread, objCVideoTrackSource)];
+}
+
+- (NSString *)description {
+  NSString *stateString = [[self class] stringForState:self.state];
+  return [NSString stringWithFormat:@"RTCVideoSource( %p ): %@", self, stateString];
+}
+
+- (void)capturer:(RTCVideoCapturer *)capturer didCaptureVideoFrame:(RTCVideoFrame *)frame {
+  getObjCVideoSource(_nativeVideoSource)->OnCapturedFrame(frame);
+}
+
+- (void)adaptOutputFormatToWidth:(int)width height:(int)height fps:(int)fps {
+  getObjCVideoSource(_nativeVideoSource)->OnOutputFormatRequest(width, height, fps);
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::VideoTrackSourceInterface>)nativeVideoSource {
+  return _nativeVideoSource;
+}
+
+@end
diff --git a/sdk/objc/api/peerconnection/RTCVideoTrack+Private.h b/sdk/objc/api/peerconnection/RTCVideoTrack+Private.h
new file mode 100644
index 0000000..176366a
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoTrack+Private.h
@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2015 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 "RTCVideoTrack.h"
+
+#include "api/mediastreaminterface.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCVideoTrack ()
+
+/** VideoTrackInterface created or passed in at construction. */
+@property(nonatomic, readonly) rtc::scoped_refptr<webrtc::VideoTrackInterface> nativeVideoTrack;
+
+/** Initialize an RTCVideoTrack with its source and an id. */
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                         source:(RTCVideoSource *)source
+                        trackId:(NSString *)trackId;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoTrack.h b/sdk/objc/api/peerconnection/RTCVideoTrack.h
new file mode 100644
index 0000000..547f4d4
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoTrack.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2015 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 "RTCMediaStreamTrack.h"
+
+#import "RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol RTCVideoRenderer;
+@class RTCPeerConnectionFactory;
+@class RTCVideoSource;
+
+RTC_EXPORT
+@interface RTCVideoTrack : RTCMediaStreamTrack
+
+/** The video source for this video track. */
+@property(nonatomic, readonly) RTCVideoSource *source;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/** Register a renderer that will render all frames received on this track. */
+- (void)addRenderer:(id<RTCVideoRenderer>)renderer;
+
+/** Deregister a renderer. */
+- (void)removeRenderer:(id<RTCVideoRenderer>)renderer;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/peerconnection/RTCVideoTrack.mm b/sdk/objc/api/peerconnection/RTCVideoTrack.mm
new file mode 100644
index 0000000..77936a6
--- /dev/null
+++ b/sdk/objc/api/peerconnection/RTCVideoTrack.mm
@@ -0,0 +1,113 @@
+/*
+ *  Copyright 2015 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 "RTCVideoTrack+Private.h"
+
+#import "RTCMediaStreamTrack+Private.h"
+#import "RTCPeerConnectionFactory+Private.h"
+#import "RTCVideoSource+Private.h"
+#import "api/RTCVideoRendererAdapter+Private.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCVideoTrack {
+  NSMutableArray *_adapters;
+}
+
+@synthesize source = _source;
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                         source:(RTCVideoSource *)source
+                        trackId:(NSString *)trackId {
+  NSParameterAssert(factory);
+  NSParameterAssert(source);
+  NSParameterAssert(trackId.length);
+  std::string nativeId = [NSString stdStringForString:trackId];
+  rtc::scoped_refptr<webrtc::VideoTrackInterface> track =
+      factory.nativeFactory->CreateVideoTrack(nativeId,
+                                              source.nativeVideoSource);
+  if (self = [self initWithFactory:factory nativeTrack:track type:RTCMediaStreamTrackTypeVideo]) {
+    _source = source;
+  }
+  return self;
+}
+
+- (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
+                    nativeTrack:
+                        (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeMediaTrack
+                           type:(RTCMediaStreamTrackType)type {
+  NSParameterAssert(factory);
+  NSParameterAssert(nativeMediaTrack);
+  NSParameterAssert(type == RTCMediaStreamTrackTypeVideo);
+  if (self = [super initWithFactory:factory nativeTrack:nativeMediaTrack type:type]) {
+    _adapters = [NSMutableArray array];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  for (RTCVideoRendererAdapter *adapter in _adapters) {
+    self.nativeVideoTrack->RemoveSink(adapter.nativeVideoRenderer);
+  }
+}
+
+- (RTCVideoSource *)source {
+  if (!_source) {
+    rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> source =
+        self.nativeVideoTrack->GetSource();
+    if (source) {
+      _source =
+          [[RTCVideoSource alloc] initWithFactory:self.factory nativeVideoSource:source.get()];
+    }
+  }
+  return _source;
+}
+
+- (void)addRenderer:(id<RTCVideoRenderer>)renderer {
+  // Make sure we don't have this renderer yet.
+  for (RTCVideoRendererAdapter *adapter in _adapters) {
+    if (adapter.videoRenderer == renderer) {
+      NSAssert(NO, @"|renderer| is already attached to this track");
+      return;
+    }
+  }
+  // Create a wrapper that provides a native pointer for us.
+  RTCVideoRendererAdapter* adapter =
+      [[RTCVideoRendererAdapter alloc] initWithNativeRenderer:renderer];
+  [_adapters addObject:adapter];
+  self.nativeVideoTrack->AddOrUpdateSink(adapter.nativeVideoRenderer,
+                                         rtc::VideoSinkWants());
+}
+
+- (void)removeRenderer:(id<RTCVideoRenderer>)renderer {
+  __block NSUInteger indexToRemove = NSNotFound;
+  [_adapters enumerateObjectsUsingBlock:^(RTCVideoRendererAdapter *adapter,
+                                          NSUInteger idx,
+                                          BOOL *stop) {
+    if (adapter.videoRenderer == renderer) {
+      indexToRemove = idx;
+      *stop = YES;
+    }
+  }];
+  if (indexToRemove == NSNotFound) {
+    return;
+  }
+  RTCVideoRendererAdapter *adapterToRemove =
+      [_adapters objectAtIndex:indexToRemove];
+  self.nativeVideoTrack->RemoveSink(adapterToRemove.nativeVideoRenderer);
+  [_adapters removeObjectAtIndex:indexToRemove];
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::VideoTrackInterface>)nativeVideoTrack {
+  return static_cast<webrtc::VideoTrackInterface *>(self.nativeTrack.get());
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoCodecConstants.h b/sdk/objc/api/video_codec/RTCVideoCodecConstants.h
new file mode 100644
index 0000000..1d03f59
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoCodecConstants.h
@@ -0,0 +1,16 @@
+/*
+ *  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 "base/RTCMacros.h"
+
+RTC_EXPORT extern NSString *const kRTCVideoCodecVp8Name;
+RTC_EXPORT extern NSString *const kRTCVideoCodecVp9Name;
diff --git a/sdk/objc/api/video_codec/RTCVideoCodecConstants.mm b/sdk/objc/api/video_codec/RTCVideoCodecConstants.mm
new file mode 100644
index 0000000..acbf126
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoCodecConstants.mm
@@ -0,0 +1,17 @@
+/*
+ *  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 "RTCVideoCodecConstants.h"
+
+#include "media/base/mediaconstants.h"
+
+NSString *const kRTCVideoCodecVp8Name = @(cricket::kVp8CodecName);
+NSString *const kRTCVideoCodecVp9Name = @(cricket::kVp9CodecName);
diff --git a/sdk/objc/api/video_codec/RTCVideoDecoderVP8.h b/sdk/objc/api/video_codec/RTCVideoDecoderVP8.h
new file mode 100644
index 0000000..e5050ff
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoDecoderVP8.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+#import "RTCVideoDecoder.h"
+
+RTC_EXPORT
+@interface RTCVideoDecoderVP8 : NSObject
+
+/* This returns a VP8 decoder that can be returned from a RTCVideoDecoderFactory injected into
+ * RTCPeerConnectionFactory. Even though it implements the RTCVideoDecoder protocol, it can not be
+ * used independently from the RTCPeerConnectionFactory.
+ */
++ (id<RTCVideoDecoder>)vp8Decoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoDecoderVP8.mm b/sdk/objc/api/video_codec/RTCVideoDecoderVP8.mm
new file mode 100644
index 0000000..9750bd8
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoDecoderVP8.mm
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCVideoDecoderVP8.h"
+#import "RTCWrappedNativeVideoDecoder.h"
+
+#include "modules/video_coding/codecs/vp8/include/vp8.h"
+
+@implementation RTCVideoDecoderVP8
+
++ (id<RTCVideoDecoder>)vp8Decoder {
+  return [[RTCWrappedNativeVideoDecoder alloc]
+      initWithNativeDecoder:std::unique_ptr<webrtc::VideoDecoder>(webrtc::VP8Decoder::Create())];
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoDecoderVP9.h b/sdk/objc/api/video_codec/RTCVideoDecoderVP9.h
new file mode 100644
index 0000000..06d0a03
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoDecoderVP9.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+#import "RTCVideoDecoder.h"
+
+RTC_EXPORT
+@interface RTCVideoDecoderVP9 : NSObject
+
+/* This returns a VP9 decoder that can be returned from a RTCVideoDecoderFactory injected into
+ * RTCPeerConnectionFactory. Even though it implements the RTCVideoDecoder protocol, it can not be
+ * used independently from the RTCPeerConnectionFactory.
+ */
++ (id<RTCVideoDecoder>)vp9Decoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoDecoderVP9.mm b/sdk/objc/api/video_codec/RTCVideoDecoderVP9.mm
new file mode 100644
index 0000000..48582fe
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoDecoderVP9.mm
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCVideoDecoderVP9.h"
+#import "RTCWrappedNativeVideoDecoder.h"
+
+#include "modules/video_coding/codecs/vp9/include/vp9.h"
+
+@implementation RTCVideoDecoderVP9
+
++ (id<RTCVideoDecoder>)vp9Decoder {
+  return [[RTCWrappedNativeVideoDecoder alloc]
+      initWithNativeDecoder:std::unique_ptr<webrtc::VideoDecoder>(webrtc::VP9Decoder::Create())];
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoEncoderVP8.h b/sdk/objc/api/video_codec/RTCVideoEncoderVP8.h
new file mode 100644
index 0000000..e3a50f2
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoEncoderVP8.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+#import "RTCVideoEncoder.h"
+
+RTC_EXPORT
+@interface RTCVideoEncoderVP8 : NSObject
+
+/* This returns a VP8 encoder that can be returned from a RTCVideoEncoderFactory injected into
+ * RTCPeerConnectionFactory. Even though it implements the RTCVideoEncoder protocol, it can not be
+ * used independently from the RTCPeerConnectionFactory.
+ */
++ (id<RTCVideoEncoder>)vp8Encoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoEncoderVP8.mm b/sdk/objc/api/video_codec/RTCVideoEncoderVP8.mm
new file mode 100644
index 0000000..677f6dd
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoEncoderVP8.mm
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCVideoEncoderVP8.h"
+#import "RTCWrappedNativeVideoEncoder.h"
+
+#include "modules/video_coding/codecs/vp8/include/vp8.h"
+
+@implementation RTCVideoEncoderVP8
+
++ (id<RTCVideoEncoder>)vp8Encoder {
+  return [[RTCWrappedNativeVideoEncoder alloc]
+      initWithNativeEncoder:std::unique_ptr<webrtc::VideoEncoder>(webrtc::VP8Encoder::Create())];
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoEncoderVP9.h b/sdk/objc/api/video_codec/RTCVideoEncoderVP9.h
new file mode 100644
index 0000000..955f382
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoEncoderVP9.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCMacros.h"
+#import "RTCVideoEncoder.h"
+
+RTC_EXPORT
+@interface RTCVideoEncoderVP9 : NSObject
+
+/* This returns a VP9 encoder that can be returned from a RTCVideoEncoderFactory injected into
+ * RTCPeerConnectionFactory. Even though it implements the RTCVideoEncoder protocol, it can not be
+ * used independently from the RTCPeerConnectionFactory.
+ */
++ (id<RTCVideoEncoder>)vp9Encoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCVideoEncoderVP9.mm b/sdk/objc/api/video_codec/RTCVideoEncoderVP9.mm
new file mode 100644
index 0000000..a5d8408
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCVideoEncoderVP9.mm
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCVideoEncoderVP9.h"
+#import "RTCWrappedNativeVideoEncoder.h"
+
+#include "modules/video_coding/codecs/vp9/include/vp9.h"
+
+@implementation RTCVideoEncoderVP9
+
++ (id<RTCVideoEncoder>)vp9Encoder {
+  return [[RTCWrappedNativeVideoEncoder alloc]
+      initWithNativeEncoder:std::unique_ptr<webrtc::VideoEncoder>(webrtc::VP9Encoder::Create())];
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.h b/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.h
new file mode 100644
index 0000000..b5694c7
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.h
@@ -0,0 +1,25 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "base/RTCVideoDecoder.h"
+
+#include "api/video_codecs/video_decoder.h"
+#include "media/base/codec.h"
+
+@interface RTCWrappedNativeVideoDecoder : NSObject <RTCVideoDecoder>
+
+- (instancetype)initWithNativeDecoder:(std::unique_ptr<webrtc::VideoDecoder>)decoder;
+
+/* This moves the ownership of the wrapped decoder to the caller. */
+- (std::unique_ptr<webrtc::VideoDecoder>)releaseWrappedDecoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.mm b/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.mm
new file mode 100644
index 0000000..6423c7a
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCWrappedNativeVideoDecoder.mm
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCWrappedNativeVideoDecoder.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCWrappedNativeVideoDecoder {
+  std::unique_ptr<webrtc::VideoDecoder> _wrappedDecoder;
+}
+
+- (instancetype)initWithNativeDecoder:(std::unique_ptr<webrtc::VideoDecoder>)decoder {
+  if (self = [super init]) {
+    _wrappedDecoder = std::move(decoder);
+  }
+
+  return self;
+}
+
+- (std::unique_ptr<webrtc::VideoDecoder>)releaseWrappedDecoder {
+  return std::move(_wrappedDecoder);
+}
+
+#pragma mark - RTCVideoDecoder
+
+- (void)setCallback:(RTCVideoDecoderCallback)callback {
+  RTC_NOTREACHED();
+}
+
+- (NSInteger)startDecodeWithNumberOfCores:(int)numberOfCores {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSInteger)startDecodeWithSettings:(RTCVideoEncoderSettings *)settings
+                       numberOfCores:(int)numberOfCores {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSInteger)releaseDecoder {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSInteger)decode:(RTCEncodedImage *)encodedImage
+        missingFrames:(BOOL)missingFrames
+    codecSpecificInfo:(nullable id<RTCCodecSpecificInfo>)info
+         renderTimeMs:(int64_t)renderTimeMs {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSString *)implementationName {
+  RTC_NOTREACHED();
+  return nil;
+}
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.h b/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.h
new file mode 100644
index 0000000..b4ef882
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "base/RTCVideoEncoder.h"
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_encoder.h"
+#include "media/base/codec.h"
+
+@interface RTCWrappedNativeVideoEncoder : NSObject <RTCVideoEncoder>
+
+- (instancetype)initWithNativeEncoder:(std::unique_ptr<webrtc::VideoEncoder>)encoder;
+
+/* This moves the ownership of the wrapped encoder to the caller. */
+- (std::unique_ptr<webrtc::VideoEncoder>)releaseWrappedEncoder;
+
+@end
diff --git a/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.mm b/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.mm
new file mode 100644
index 0000000..ebfba2c
--- /dev/null
+++ b/sdk/objc/api/video_codec/RTCWrappedNativeVideoEncoder.mm
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "RTCWrappedNativeVideoEncoder.h"
+#import "helpers/NSString+StdString.h"
+
+@implementation RTCWrappedNativeVideoEncoder {
+  std::unique_ptr<webrtc::VideoEncoder> _wrappedEncoder;
+}
+
+- (instancetype)initWithNativeEncoder:(std::unique_ptr<webrtc::VideoEncoder>)encoder {
+  if (self = [super init]) {
+    _wrappedEncoder = std::move(encoder);
+  }
+
+  return self;
+}
+
+- (std::unique_ptr<webrtc::VideoEncoder>)releaseWrappedEncoder {
+  return std::move(_wrappedEncoder);
+}
+
+#pragma mark - RTCVideoEncoder
+
+- (void)setCallback:(RTCVideoEncoderCallback)callback {
+  RTC_NOTREACHED();
+}
+
+- (NSInteger)startEncodeWithSettings:(RTCVideoEncoderSettings *)settings
+                       numberOfCores:(int)numberOfCores {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSInteger)releaseEncoder {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSInteger)encode:(RTCVideoFrame *)frame
+    codecSpecificInfo:(nullable id<RTCCodecSpecificInfo>)info
+           frameTypes:(NSArray<NSNumber *> *)frameTypes {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (int)setBitrate:(uint32_t)bitrateKbit framerate:(uint32_t)framerate {
+  RTC_NOTREACHED();
+  return 0;
+}
+
+- (NSString *)implementationName {
+  RTC_NOTREACHED();
+  return nil;
+}
+
+- (RTCVideoEncoderQpThresholds *)scalingSettings {
+  RTC_NOTREACHED();
+  return nil;
+}
+
+@end
diff --git a/sdk/objc/api/video_frame_buffer/RTCI420Buffer+Private.h b/sdk/objc/api/video_frame_buffer/RTCI420Buffer+Private.h
new file mode 100644
index 0000000..97bc141
--- /dev/null
+++ b/sdk/objc/api/video_frame_buffer/RTCI420Buffer+Private.h
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCI420Buffer.h"
+
+#include "api/video/i420_buffer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface RTCI420Buffer () {
+ @protected
+  rtc::scoped_refptr<webrtc::I420BufferInterface> _i420Buffer;
+}
+
+/** Initialize an RTCI420Buffer with its backing I420BufferInterface. */
+- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer;
+- (rtc::scoped_refptr<webrtc::I420BufferInterface>)nativeI420Buffer;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/video_frame_buffer/RTCI420Buffer.h b/sdk/objc/api/video_frame_buffer/RTCI420Buffer.h
new file mode 100644
index 0000000..dc26134
--- /dev/null
+++ b/sdk/objc/api/video_frame_buffer/RTCI420Buffer.h
@@ -0,0 +1,23 @@
+/*
+ *  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 <AVFoundation/AVFoundation.h>
+
+#import "base/RTCI420Buffer.h"
+#import "base/RTCMacros.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** RTCI420Buffer implements the RTCI420Buffer protocol */
+RTC_EXPORT
+@interface RTCI420Buffer : NSObject <RTCI420Buffer>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/video_frame_buffer/RTCI420Buffer.mm b/sdk/objc/api/video_frame_buffer/RTCI420Buffer.mm
new file mode 100644
index 0000000..babd93c
--- /dev/null
+++ b/sdk/objc/api/video_frame_buffer/RTCI420Buffer.mm
@@ -0,0 +1,138 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCI420Buffer+Private.h"
+
+#include "api/video/i420_buffer.h"
+
+#if !defined(NDEBUG) && defined(WEBRTC_IOS)
+#import <UIKit/UIKit.h>
+#include "third_party/libyuv/include/libyuv.h"
+#endif
+
+@implementation RTCI420Buffer
+
+- (instancetype)initWithWidth:(int)width height:(int)height {
+  if (self = [super init]) {
+    _i420Buffer = webrtc::I420Buffer::Create(width, height);
+  }
+
+  return self;
+}
+
+- (instancetype)initWithWidth:(int)width
+                       height:(int)height
+                        dataY:(const uint8_t *)dataY
+                        dataU:(const uint8_t *)dataU
+                        dataV:(const uint8_t *)dataV {
+  if (self = [super init]) {
+    _i420Buffer = webrtc::I420Buffer::Copy(
+        width, height, dataY, width, dataU, (width + 1) / 2, dataV, (width + 1) / 2);
+  }
+  return self;
+}
+
+- (instancetype)initWithWidth:(int)width
+                       height:(int)height
+                      strideY:(int)strideY
+                      strideU:(int)strideU
+                      strideV:(int)strideV {
+  if (self = [super init]) {
+    _i420Buffer = webrtc::I420Buffer::Create(width, height, strideY, strideU, strideV);
+  }
+
+  return self;
+}
+
+- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer {
+  if (self = [super init]) {
+    _i420Buffer = i420Buffer;
+  }
+
+  return self;
+}
+
+- (int)width {
+  return _i420Buffer->width();
+}
+
+- (int)height {
+  return _i420Buffer->height();
+}
+
+- (int)strideY {
+  return _i420Buffer->StrideY();
+}
+
+- (int)strideU {
+  return _i420Buffer->StrideU();
+}
+
+- (int)strideV {
+  return _i420Buffer->StrideV();
+}
+
+- (int)chromaWidth {
+  return _i420Buffer->ChromaWidth();
+}
+
+- (int)chromaHeight {
+  return _i420Buffer->ChromaHeight();
+}
+
+- (const uint8_t *)dataY {
+  return _i420Buffer->DataY();
+}
+
+- (const uint8_t *)dataU {
+  return _i420Buffer->DataU();
+}
+
+- (const uint8_t *)dataV {
+  return _i420Buffer->DataV();
+}
+
+- (id<RTCI420Buffer>)toI420 {
+  return self;
+}
+
+#pragma mark - Private
+
+- (rtc::scoped_refptr<webrtc::I420BufferInterface>)nativeI420Buffer {
+  return _i420Buffer;
+}
+
+#pragma mark - Debugging
+
+#if !defined(NDEBUG) && defined(WEBRTC_IOS)
+- (id)debugQuickLookObject {
+  UIGraphicsBeginImageContext(CGSizeMake(_i420Buffer->width(), _i420Buffer->height()));
+  CGContextRef c = UIGraphicsGetCurrentContext();
+  uint8_t *ctxData = (uint8_t *)CGBitmapContextGetData(c);
+
+  libyuv::I420ToARGB(_i420Buffer->DataY(),
+                     _i420Buffer->StrideY(),
+                     _i420Buffer->DataU(),
+                     _i420Buffer->StrideU(),
+                     _i420Buffer->DataV(),
+                     _i420Buffer->StrideV(),
+                     ctxData,
+                     CGBitmapContextGetBytesPerRow(c),
+                     CGBitmapContextGetWidth(c),
+                     CGBitmapContextGetHeight(c));
+
+  UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+  UIGraphicsEndImageContext();
+
+  return image;
+}
+#endif
+
+@end
diff --git a/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.h b/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.h
new file mode 100644
index 0000000..aa91af2
--- /dev/null
+++ b/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.h
@@ -0,0 +1,24 @@
+/*
+ *  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 <AVFoundation/AVFoundation.h>
+
+#import "RTCI420Buffer.h"
+#import "base/RTCMacros.h"
+#import "base/RTCMutableI420Buffer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Mutable version of RTCI420Buffer */
+RTC_EXPORT
+@interface RTCMutableI420Buffer : RTCI420Buffer <RTCMutableI420Buffer>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.mm b/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.mm
new file mode 100644
index 0000000..e326fac
--- /dev/null
+++ b/sdk/objc/api/video_frame_buffer/RTCMutableI420Buffer.mm
@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCMutableI420Buffer.h"
+
+#import "RTCI420Buffer+Private.h"
+
+#include "api/video/i420_buffer.h"
+
+@implementation RTCMutableI420Buffer
+
+- (uint8_t *)mutableDataY {
+  return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataY();
+}
+
+- (uint8_t *)mutableDataU {
+  return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataU();
+}
+
+- (uint8_t *)mutableDataV {
+  return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataV();
+}
+
+@end