Use new RTCCameraVideoCapturer in AppRTCMobile.

Because the new API doesn't use constraints, refactors settings to instead have a
video resolution setting.

BUG=webrtc:7177

Review-Url: https://codereview.webrtc.org/2778163005
Cr-Commit-Position: refs/heads/master@{#17545}
diff --git a/webrtc/examples/BUILD.gn b/webrtc/examples/BUILD.gn
index ebe426f..10deaf2 100644
--- a/webrtc/examples/BUILD.gn
+++ b/webrtc/examples/BUILD.gn
@@ -192,6 +192,8 @@
       "objc/AppRTCMobile/ARDAppEngineClient.m",
       "objc/AppRTCMobile/ARDBitrateTracker.h",
       "objc/AppRTCMobile/ARDBitrateTracker.m",
+      "objc/AppRTCMobile/ARDCaptureController.h",
+      "objc/AppRTCMobile/ARDCaptureController.m",
       "objc/AppRTCMobile/ARDJoinResponse+Internal.h",
       "objc/AppRTCMobile/ARDJoinResponse.h",
       "objc/AppRTCMobile/ARDJoinResponse.m",
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
index 933dc6b..b613ec9 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
+++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
@@ -10,6 +10,7 @@
 
 #import <Foundation/Foundation.h>
 
+#import "WebRTC/RTCCameraVideoCapturer.h"
 #import "WebRTC/RTCPeerConnection.h"
 #import "WebRTC/RTCVideoTrack.h"
 
@@ -37,6 +38,9 @@
     didChangeConnectionState:(RTCIceConnectionState)state;
 
 - (void)appClient:(ARDAppClient *)client
+    didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer;
+
+- (void)appClient:(ARDAppClient *)client
     didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack;
 
 - (void)appClient:(ARDAppClient *)client
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
index ef38138..7e06612 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
+++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
@@ -12,6 +12,7 @@
 
 #import "WebRTC/RTCAVFoundationVideoSource.h"
 #import "WebRTC/RTCAudioTrack.h"
+#import "WebRTC/RTCCameraVideoCapturer.h"
 #import "WebRTC/RTCConfiguration.h"
 #import "WebRTC/RTCFileLogger.h"
 #import "WebRTC/RTCIceServer.h"
@@ -21,6 +22,7 @@
 #import "WebRTC/RTCPeerConnectionFactory.h"
 #import "WebRTC/RTCRtpSender.h"
 #import "WebRTC/RTCTracing.h"
+#import "WebRTC/RTCVideoTrack.h"
 
 #import "ARDAppEngineClient.h"
 #import "ARDJoinResponse.h"
@@ -100,6 +102,7 @@
   RTCFileLogger *_fileLogger;
   ARDTimerProxy *_statsTimer;
   ARDSettingsModel *_settings;
+  RTCVideoTrack *_localVideoTrack;
 }
 
 @synthesize shouldGetStats = _shouldGetStats;
@@ -305,6 +308,7 @@
   _isInitiator = NO;
   _hasReceivedSdp = NO;
   _messageQueue = [NSMutableArray array];
+  _localVideoTrack = nil;
 #if defined(WEBRTC_IOS)
   [_factory stopAecDump];
   [_peerConnection stopRtcEventLog];
@@ -666,10 +670,10 @@
   RTCRtpSender *sender =
       [_peerConnection senderWithKind:kRTCMediaStreamTrackKindVideo
                              streamId:kARDMediaStreamId];
-  RTCVideoTrack *track = [self createLocalVideoTrack];
-  if (track) {
-    sender.track = track;
-    [_delegate appClient:self didReceiveLocalVideoTrack:track];
+  _localVideoTrack = [self createLocalVideoTrack];
+  if (_localVideoTrack) {
+    sender.track = _localVideoTrack;
+    [_delegate appClient:self didReceiveLocalVideoTrack:_localVideoTrack];
   }
 
   return sender;
@@ -716,10 +720,9 @@
   // trying to open a local stream.
 #if !TARGET_IPHONE_SIMULATOR
   if (!_isAudioOnly) {
-    RTCMediaConstraints *cameraConstraints =
-        [self cameraConstraints];
-    RTCAVFoundationVideoSource *source =
-        [_factory avFoundationVideoSourceWithConstraints:cameraConstraints];
+    RTCVideoSource *source = [_factory videoSource];
+    RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source];
+    [_delegate appClient:self didCreateLocalCapturer:capturer];
     localVideoTrack =
         [_factory videoTrackWithSource:source
                                trackId:kARDVideoTrackId];
@@ -764,13 +767,6 @@
    return constraints;
 }
 
-- (RTCMediaConstraints *)cameraConstraints {
-  RTCMediaConstraints *cameraConstraints = [[RTCMediaConstraints alloc]
-      initWithMandatoryConstraints:nil
-               optionalConstraints:[_settings currentMediaConstraintFromStoreAsRTCDictionary]];
-  return cameraConstraints;
-}
-
 - (RTCMediaConstraints *)defaultAnswerConstraints {
   return [self defaultOfferConstraints];
 }
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.h b/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.h
new file mode 100644
index 0000000..bdae93a
--- /dev/null
+++ b/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.h
@@ -0,0 +1,24 @@
+/*
+ *  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.
+ */
+
+#include <WebRTC/RTCCameraVideoCapturer.h>
+
+@class ARDSettingsModel;
+
+// Controls the camera. Handles starting the capture, switching cameras etc.
+@interface ARDCaptureController : NSObject
+
+- (instancetype)initWithCapturer:(RTCCameraVideoCapturer *)capturer
+                        settings:(ARDSettingsModel *)settings;
+- (void)startCapture;
+- (void)stopCapture;
+- (void)switchCamera;
+
+@end
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m b/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m
new file mode 100644
index 0000000..328c422
--- /dev/null
+++ b/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m
@@ -0,0 +1,92 @@
+/*
+ *  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 "ARDCaptureController.h"
+
+#import "ARDSettingsModel.h"
+
+@implementation ARDCaptureController {
+  RTCCameraVideoCapturer *_capturer;
+  ARDSettingsModel *_settings;
+  BOOL _usingFrontCamera;
+}
+
+- (instancetype)initWithCapturer:(RTCCameraVideoCapturer *)capturer
+                        settings:(ARDSettingsModel *)settings {
+  if ([super init]) {
+    _capturer = capturer;
+    _settings = settings;
+    _usingFrontCamera = YES;
+  }
+
+  return self;
+}
+
+- (void)startCapture {
+  AVCaptureDevicePosition position =
+      _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
+  AVCaptureDevice *device = [self findDeviceForPosition:position];
+  AVCaptureDeviceFormat *format = [self selectFormatForDevice:device];
+  int fps = [self selectFpsForFormat:format];
+
+  [_capturer startCaptureWithDevice:device format:format fps:fps];
+}
+
+- (void)stopCapture {
+  [_capturer stopCapture];
+}
+
+- (void)switchCamera {
+  _usingFrontCamera = !_usingFrontCamera;
+  [self startCapture];
+}
+
+#pragma mark - Private
+
+- (AVCaptureDevice *)findDeviceForPosition:(AVCaptureDevicePosition)position {
+  NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
+  for (AVCaptureDevice *device in captureDevices) {
+    if (device.position == position) {
+      return device;
+    }
+  }
+  return captureDevices[0];
+}
+
+- (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device {
+  NSArray<AVCaptureDeviceFormat *> *formats =
+      [RTCCameraVideoCapturer supportedFormatsForDevice:device];
+  int targetWidth = [_settings currentVideoResolutionWidthFromStore];
+  int targetHeight = [_settings currentVideoResolutionHeightFromStore];
+  AVCaptureDeviceFormat *selectedFormat = nil;
+  int currentDiff = INT_MAX;
+
+  for (AVCaptureDeviceFormat *format in formats) {
+    CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
+    int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height);
+    if (diff < currentDiff) {
+      selectedFormat = format;
+      currentDiff = diff;
+    }
+  }
+
+  NSAssert(selectedFormat != nil, @"No suitable capture format found.");
+  return selectedFormat;
+}
+
+- (int)selectFpsForFormat:(AVCaptureDeviceFormat *)format {
+  Float64 maxFramerate = 0;
+  for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) {
+    maxFramerate = fmax(maxFramerate, fpsRange.maxFrameRate);
+  }
+  return maxFramerate;
+}
+
+@end
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel+Private.h b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel+Private.h
index eba99d7..08d863d 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel+Private.h
+++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel+Private.h
@@ -16,7 +16,5 @@
 NS_ASSUME_NONNULL_BEGIN
 @interface ARDSettingsModel ()
 - (ARDSettingsStore *)settingsStore;
-- (nullable NSString *)currentVideoResolutionWidthFromStore;
-- (nullable NSString *)currentVideoResolutionHeightFromStore;
 @end
 NS_ASSUME_NONNULL_END
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h
index 0eb7b31..1787bb2 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h
+++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h
@@ -14,12 +14,9 @@
 /**
  * Model class for user defined settings.
  *
- * Currently used for streaming media constraints and bitrate only.
- * In future audio media constraints support can be added as well.
- * Offers list of avaliable video resolutions that can construct streaming media constraint.
- * Exposes methods for reading and storing media constraints from persistent store.
- * Also translates current user defined media constraint into RTCMediaConstraints
- * dictionary.
+ * Handles storing the settings and provides default values if setting is not
+ * set. Also provides list of available options for different settings. Stores
+ * for example video codec, video resolution and maximum bitrate.
  */
 @interface ARDSettingsModel : NSObject
 
@@ -29,24 +26,26 @@
  * The capture resolutions are represented as strings in the following format
  * [width]x[height]
  */
-- (NSArray<NSString *> *)availableVideoResoultionsMediaConstraints;
+- (NSArray<NSString *> *)availableVideoResolutions;
 
 /**
- * Returns current video resolution media constraint string.
- * If no constraint is in store, default value of 640x480 is returned.
+ * Returns current video resolution string.
+ * If no resolution is in store, default value of 640x480 is returned.
  * When defaulting to value, the default is saved in store for consistency reasons.
  */
-- (NSString *)currentVideoResoultionConstraintFromStore;
+- (NSString *)currentVideoResolutionSettingFromStore;
+- (int)currentVideoResolutionWidthFromStore;
+- (int)currentVideoResolutionHeightFromStore;
 
 /**
- * Stores the provided video resolution media constraint string into the store.
+ * Stores the provided video resolution string into the store.
  *
- * If the provided constraint is no part of the available video resolutions
+ * If the provided resolution is no part of the available video resolutions
  * the store operation will not be executed and NO will be returned.
- * @param constraint the string to be stored.
+ * @param resolution the string to be stored.
  * @return YES/NO depending on success.
  */
-- (BOOL)storeVideoResoultionConstraint:(NSString *)constraint;
+- (BOOL)storeVideoResolutionSetting:(NSString *)resolution;
 
 /**
  * Returns array of available video codecs.
@@ -61,7 +60,7 @@
 /**
  * Stores the provided video codec setting into the store.
  *
- * If the provided constraint is not part of the available video codecs
+ * If the provided video codec is not part of the available video codecs
  * the store operation will not be executed and NO will be returned.
  * @param video codec settings the string to be stored.
  * @return YES/NO depending on success.
@@ -69,14 +68,6 @@
 - (BOOL)storeVideoCodecSetting:(NSString *)videoCodec;
 
 /**
- * Converts the current media constraints from store into dictionary with RTCMediaConstraints
- * values.
- *
- * @return NSDictionary with RTC width and height parameters
- */
-- (nullable NSDictionary *)currentMediaConstraintFromStoreAsRTCDictionary;
-
-/**
  * Returns current max bitrate setting from store if present.
  */
 - (nullable NSNumber *)currentMaxBitrateSettingFromStore;
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m
index 7514689..ecb6ab3 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m
+++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m
@@ -28,25 +28,25 @@
 
 @implementation ARDSettingsModel
 
-- (NSArray<NSString *> *)availableVideoResoultionsMediaConstraints {
+- (NSArray<NSString *> *)availableVideoResolutions {
   return videoResolutionsStaticValues();
 }
 
-- (NSString *)currentVideoResoultionConstraintFromStore {
-  NSString *constraint = [[self settingsStore] videoResolutionConstraints];
-  if (!constraint) {
-    constraint = [self defaultVideoResolutionMediaConstraint];
+- (NSString *)currentVideoResolutionSettingFromStore {
+  NSString *resolution = [[self settingsStore] videoResolution];
+  if (!resolution) {
+    resolution = [self defaultVideoResolutionSetting];
     // To ensure consistency add the default to the store.
-    [[self settingsStore] setVideoResolutionConstraints:constraint];
+    [[self settingsStore] setVideoResolution:resolution];
   }
-  return constraint;
+  return resolution;
 }
 
-- (BOOL)storeVideoResoultionConstraint:(NSString *)constraint {
-  if (![[self availableVideoResoultionsMediaConstraints] containsObject:constraint]) {
+- (BOOL)storeVideoResolutionSetting:(NSString *)resolution {
+  if (![[self availableVideoResolutions] containsObject:resolution]) {
     return NO;
   }
-  [[self settingsStore] setVideoResolutionConstraints:constraint];
+  [[self settingsStore] setVideoResolution:resolution];
   return YES;
 }
 
@@ -88,54 +88,37 @@
   return _settingsStore;
 }
 
-- (nullable NSString *)currentVideoResolutionWidthFromStore {
-  NSString *mediaConstraintFromStore = [self currentVideoResoultionConstraintFromStore];
+- (int)currentVideoResolutionWidthFromStore {
+  NSString *resolution = [self currentVideoResolutionSettingFromStore];
 
-  return [self videoResolutionComponentAtIndex:0 inConstraintsString:mediaConstraintFromStore];
+  return [self videoResolutionComponentAtIndex:0 inString:resolution];
 }
 
-- (nullable NSString *)currentVideoResolutionHeightFromStore {
-  NSString *mediaConstraintFromStore = [self currentVideoResoultionConstraintFromStore];
-  return [self videoResolutionComponentAtIndex:1 inConstraintsString:mediaConstraintFromStore];
+- (int)currentVideoResolutionHeightFromStore {
+  NSString *resolution = [self currentVideoResolutionSettingFromStore];
+  return [self videoResolutionComponentAtIndex:1 inString:resolution];
 }
 
 #pragma mark -
 
-- (NSString *)defaultVideoResolutionMediaConstraint {
+- (NSString *)defaultVideoResolutionSetting {
   return videoResolutionsStaticValues()[0];
 }
 
-- (nullable NSString *)videoResolutionComponentAtIndex:(int)index
-                                   inConstraintsString:(NSString *)constraint {
+- (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolution {
   if (index != 0 && index != 1) {
-    return nil;
+    return 0;
   }
-  NSArray *components = [constraint componentsSeparatedByString:@"x"];
+  NSArray<NSString *> *components = [resolution componentsSeparatedByString:@"x"];
   if (components.count != 2) {
-    return nil;
+    return 0;
   }
-  return components[index];
+  return components[index].intValue;
 }
 
 - (NSString *)defaultVideoCodecSetting {
   return videoCodecsStaticValues()[0];
 }
 
-#pragma mark - Conversion to RTCMediaConstraints
-
-- (nullable NSDictionary *)currentMediaConstraintFromStoreAsRTCDictionary {
-  NSDictionary *mediaConstraintsDictionary = nil;
-
-  NSString *widthConstraint = [self currentVideoResolutionWidthFromStore];
-  NSString *heightConstraint = [self currentVideoResolutionHeightFromStore];
-  if (widthConstraint && heightConstraint) {
-    mediaConstraintsDictionary = @{
-      kRTCMediaConstraintsMinWidth : widthConstraint,
-      kRTCMediaConstraintsMinHeight : heightConstraint
-    };
-  }
-  return mediaConstraintsDictionary;
-}
-
 @end
 NS_ASSUME_NONNULL_END
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h
index b010b7f..3dd0f64 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h
+++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h
@@ -19,20 +19,10 @@
  */
 @interface ARDSettingsStore : NSObject
 
+@property(nonatomic) NSString *videoResolution;
 @property(nonatomic) NSString *videoCodec;
 
 /**
- * Returns current video resolution media constraint string stored in the store.
- */
-- (nullable NSString *)videoResolutionConstraints;
-
-/**
- * Stores the provided value as video resolution media constraint.
- * @param value the string to be stored
- */
-- (void)setVideoResolutionConstraints:(NSString *)value;
-
-/**
  * Returns current max bitrate number stored in the store.
  */
 - (nullable NSNumber *)maxBitrate;
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m
index 6d9fa5b..e25b288 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m
+++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m
@@ -10,7 +10,7 @@
 
 #import "ARDSettingsStore.h"
 
-static NSString *const kMediaConstraintsKey = @"rtc_video_resolution_media_constraints_key";
+static NSString *const kVideoResolutionKey = @"rtc_video_resolution_key";
 static NSString *const kVideoCodecKey = @"rtc_video_codec_key";
 static NSString *const kBitrateKey = @"rtc_max_bitrate_key";
 
@@ -30,12 +30,12 @@
   return _storage;
 }
 
-- (nullable NSString *)videoResolutionConstraints {
-  return [self.storage objectForKey:kMediaConstraintsKey];
+- (NSString *)videoResolution {
+  return [self.storage objectForKey:kVideoResolutionKey];
 }
 
-- (void)setVideoResolutionConstraints:(NSString *)constraintsString {
-  [self.storage setObject:constraintsString forKey:kMediaConstraintsKey];
+- (void)setVideoResolution:(NSString *)resolution {
+  [self.storage setObject:resolution forKey:kVideoResolutionKey];
   [self.storage synchronize];
 }
 
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
index fb59dd2..3944480 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
@@ -14,7 +14,7 @@
 NS_ASSUME_NONNULL_BEGIN
 
 typedef NS_ENUM(int, ARDSettingsSections) {
-  ARDSettingsSectionMediaConstraints = 0,
+  ARDSettingsSectionVideoResolution = 0,
   ARDSettingsSectionVideoCodec,
   ARDSettingsSectionBitRate,
 };
@@ -46,9 +46,9 @@
 
 - (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
-  [self addCheckmarkInSection:ARDSettingsSectionMediaConstraints
-                    withArray:[self mediaConstraintsArray]
-                    selecting:[_settingsModel currentVideoResoultionConstraintFromStore]];
+  [self addCheckmarkInSection:ARDSettingsSectionVideoResolution
+                    withArray:[self videoResolutionArray]
+                    selecting:[_settingsModel currentVideoResolutionSettingFromStore]];
   [self addCheckmarkInSection:ARDSettingsSectionVideoCodec
                     withArray:[self videoCodecArray]
                     selecting:[_settingsModel currentVideoCodecSettingFromStore]];
@@ -60,8 +60,8 @@
 
 #pragma mark - Data source
 
-- (NSArray<NSString *> *)mediaConstraintsArray {
-  return _settingsModel.availableVideoResoultionsMediaConstraints;
+- (NSArray<NSString *> *)videoResolutionArray {
+  return _settingsModel.availableVideoResolutions;
 }
 
 - (NSArray<NSString *> *)videoCodecArray {
@@ -102,8 +102,8 @@
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
   switch (section) {
-    case ARDSettingsSectionMediaConstraints:
-      return self.mediaConstraintsArray.count;
+    case ARDSettingsSectionVideoResolution:
+      return self.videoResolutionArray.count;
     case ARDSettingsSectionVideoCodec:
       return self.videoCodecArray.count;
     default:
@@ -137,8 +137,8 @@
 - (nullable NSString *)tableView:(UITableView *)tableView
          titleForHeaderInSection:(NSInteger)section {
   switch (section) {
-    case ARDSettingsSectionMediaConstraints:
-      return @"Media constraints";
+    case ARDSettingsSectionVideoResolution:
+      return @"Video resolution";
     case ARDSettingsSectionVideoCodec:
       return @"Video codec";
     case ARDSettingsSectionBitRate:
@@ -151,8 +151,8 @@
 - (UITableViewCell *)tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   switch (indexPath.section) {
-    case ARDSettingsSectionMediaConstraints:
-      return [self mediaConstraintsTableViewCellForTableView:tableView atIndexPath:indexPath];
+    case ARDSettingsSectionVideoResolution:
+      return [self videoResolutionTableViewCellForTableView:tableView atIndexPath:indexPath];
 
     case ARDSettingsSectionVideoCodec:
       return [self videoCodecTableViewCellForTableView:tableView atIndexPath:indexPath];
@@ -168,8 +168,8 @@
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   switch (indexPath.section) {
-    case ARDSettingsSectionMediaConstraints:
-      [self tableView:tableView didSelectMediaConstraintsCellAtIndexPath:indexPath];
+    case ARDSettingsSectionVideoResolution:
+      [self tableView:tableView disSelectVideoResolutionAtIndex:indexPath];
       break;
 
     case ARDSettingsSectionVideoCodec:
@@ -178,28 +178,28 @@
   }
 }
 
-#pragma mark - Table view delegate(Media Constraints)
+#pragma mark - Table view delegate(Video Resolution)
 
-- (UITableViewCell *)mediaConstraintsTableViewCellForTableView:(UITableView *)tableView
-                                                   atIndexPath:(NSIndexPath *)indexPath {
-  NSString *dequeueIdentifier = @"ARDSettingsMediaConstraintsViewCellIdentifier";
+- (UITableViewCell *)videoResolutionTableViewCellForTableView:(UITableView *)tableView
+                                                  atIndexPath:(NSIndexPath *)indexPath {
+  NSString *dequeueIdentifier = @"ARDSettingsVideoResolutionViewCellIdentifier";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier];
   if (!cell) {
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                   reuseIdentifier:dequeueIdentifier];
   }
-  cell.textLabel.text = self.mediaConstraintsArray[indexPath.row];
+  cell.textLabel.text = self.videoResolutionArray[indexPath.row];
   return cell;
 }
 
 - (void)tableView:(UITableView *)tableView
-    didSelectMediaConstraintsCellAtIndexPath:(NSIndexPath *)indexPath {
+    disSelectVideoResolutionAtIndex:(NSIndexPath *)indexPath {
   [self tableView:tableView
-    updateListSelectionAtIndexPath:indexPath
-        inSection:ARDSettingsSectionMediaConstraints];
+      updateListSelectionAtIndexPath:indexPath
+                           inSection:ARDSettingsSectionVideoResolution];
 
-  NSString *mediaConstraintsString = self.mediaConstraintsArray[indexPath.row];
-  [_settingsModel storeVideoResoultionConstraint:mediaConstraintsString];
+  NSString *videoResolution = self.videoResolutionArray[indexPath.row];
+  [_settingsModel storeVideoResolutionSetting:videoResolution];
 }
 
 #pragma mark - Table view delegate(Video Codec)
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallView.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallView.m
index 869d29c..2241930 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallView.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallView.m
@@ -31,7 +31,6 @@
   UIButton *_cameraSwitchButton;
   UIButton *_hangupButton;
   CGSize _remoteVideoSize;
-  BOOL _useRearCamera;
 }
 
 @synthesize statusLabel = _statusLabel;
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
index cd42514..732e4b6 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
@@ -13,6 +13,7 @@
 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h"
 
 #import "ARDAppClient.h"
+#import "ARDCaptureController.h"
 #import "ARDSettingsModel.h"
 #import "ARDVideoCallView.h"
 #import "WebRTC/RTCAVFoundationVideoSource.h"
@@ -22,7 +23,6 @@
 
 @interface ARDVideoCallViewController () <ARDAppClientDelegate,
     ARDVideoCallViewDelegate>
-@property(nonatomic, strong) RTCVideoTrack *localVideoTrack;
 @property(nonatomic, strong) RTCVideoTrack *remoteVideoTrack;
 @property(nonatomic, readonly) ARDVideoCallView *videoCallView;
 @end
@@ -30,12 +30,11 @@
 @implementation ARDVideoCallViewController {
   ARDAppClient *_client;
   RTCVideoTrack *_remoteVideoTrack;
-  RTCVideoTrack *_localVideoTrack;
+  ARDCaptureController *_captureController;
   AVAudioSessionPortOverride _portOverride;
 }
 
 @synthesize videoCallView = _videoCallView;
-@synthesize localVideoTrack = _localVideoTrack;
 @synthesize remoteVideoTrack = _remoteVideoTrack;
 @synthesize delegate = _delegate;
 
@@ -48,6 +47,7 @@
   if (self = [super init]) {
     ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
     _delegate = delegate;
+
     _client = [[ARDAppClient alloc] initWithDelegate:self];
     [_client connectToRoomWithId:room
                         settings:settingsModel
@@ -97,8 +97,16 @@
 }
 
 - (void)appClient:(ARDAppClient *)client
+    didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer {
+  _videoCallView.localVideoView.captureSession = localCapturer.captureSession;
+  ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
+  _captureController =
+      [[ARDCaptureController alloc] initWithCapturer:localCapturer settings:settingsModel];
+  [_captureController startCapture];
+}
+
+- (void)appClient:(ARDAppClient *)client
     didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
-  self.localVideoTrack = localVideoTrack;
 }
 
 - (void)appClient:(ARDAppClient *)client
@@ -130,7 +138,7 @@
 - (void)videoCallViewDidSwitchCamera:(ARDVideoCallView *)view {
   // TODO(tkchin): Rate limit this so you can't tap continously on it.
   // Probably through an animation.
-  [self switchCamera];
+  [_captureController switchCamera];
 }
 
 - (void)videoCallViewDidChangeRoute:(ARDVideoCallView *)view {
@@ -160,20 +168,6 @@
 
 #pragma mark - Private
 
-- (void)setLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
-  if (_localVideoTrack == localVideoTrack) {
-    return;
-  }
-  _localVideoTrack = nil;
-  _localVideoTrack = localVideoTrack;
-  RTCAVFoundationVideoSource *source = nil;
-  if ([localVideoTrack.source
-          isKindOfClass:[RTCAVFoundationVideoSource class]]) {
-    source = (RTCAVFoundationVideoSource*)localVideoTrack.source;
-  }
-  _videoCallView.localVideoView.captureSession = source.captureSession;
-}
-
 - (void)setRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack {
   if (_remoteVideoTrack == remoteVideoTrack) {
     return;
@@ -187,19 +181,13 @@
 
 - (void)hangup {
   self.remoteVideoTrack = nil;
-  self.localVideoTrack = nil;
+  _videoCallView.localVideoView.captureSession = nil;
+  [_captureController stopCapture];
+  _captureController = nil;
   [_client disconnect];
   [_delegate viewControllerDidFinish:self];
 }
 
-- (void)switchCamera {
-  RTCVideoSource* source = self.localVideoTrack.source;
-  if ([source isKindOfClass:[RTCAVFoundationVideoSource class]]) {
-    RTCAVFoundationVideoSource* avSource = (RTCAVFoundationVideoSource*)source;
-    avSource.useBackCamera = !avSource.useBackCamera;
-  }
-}
-
 - (NSString *)statusTextForState:(RTCIceConnectionState)state {
   switch (state) {
     case RTCIceConnectionStateNew:
diff --git a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
index 089901e..9d36d9b 100644
--- a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
@@ -17,6 +17,7 @@
 #import "WebRTC/RTCVideoTrack.h"
 
 #import "ARDAppClient.h"
+#import "ARDCaptureController.h"
 #import "ARDSettingsModel.h"
 
 static NSUInteger const kContentWidth = 900;
@@ -299,6 +300,7 @@
   ARDAppClient* _client;
   RTCVideoTrack* _localVideoTrack;
   RTCVideoTrack* _remoteVideoTrack;
+  ARDCaptureController* _captureController;
 }
 
 - (void)dealloc {
@@ -353,6 +355,14 @@
     didChangeConnectionState:(RTCIceConnectionState)state {
 }
 
+- (void)appClient:(ARDAppClient*)client
+    didCreateLocalCapturer:(RTCCameraVideoCapturer*)localCapturer {
+  _captureController =
+      [[ARDCaptureController alloc] initWithCapturer:localCapturer
+                                            settings:[[ARDSettingsModel alloc] init]];
+  [_captureController startCapture];
+}
+
 - (void)appClient:(ARDAppClient *)client
     didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
   _localVideoTrack = localVideoTrack;
@@ -386,7 +396,7 @@
     return;
   }
 
-  [_client disconnect];
+  [self disconnect];
   ARDAppClient* client = [[ARDAppClient alloc] initWithDelegate:self];
   [client connectToRoomWithId:roomId
                      settings:[[ARDSettingsModel alloc] init]  // Use default settings.
@@ -420,6 +430,8 @@
 
 - (void)disconnect {
   [self resetUI];
+  [_captureController stopCapture];
+  _captureController = nil;
   [_client disconnect];
 }
 
diff --git a/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm b/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm
index eee18db..64e05b1 100644
--- a/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm
+++ b/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm
@@ -25,9 +25,9 @@
 
 @implementation ARDSettingsModelTests
 
-- (id)setupMockStoreWithMediaConstraintString:(NSString *)constraintString {
+- (id)setupMockStoreWithVideoResolution:(NSString *)videoResolution {
   id storeMock = [OCMockObject mockForClass:[ARDSettingsStore class]];
-  [([[storeMock stub] andReturn:constraintString]) videoResolutionConstraints];
+  [([[storeMock stub] andReturn:videoResolution])videoResolution];
 
   id partialMock = [OCMockObject partialMockForObject:_model];
   [[[partialMock stub] andReturn:storeMock] settingsStore];
@@ -40,45 +40,38 @@
 }
 
 - (void)testDefaultMediaFromStore {
-  id storeMock = [self setupMockStoreWithMediaConstraintString:nil];
-  [[storeMock expect] setVideoResolutionConstraints:@"640x480"];
+  id storeMock = [self setupMockStoreWithVideoResolution:nil];
+  [[storeMock expect] setVideoResolution:@"640x480"];
 
-  NSString *string = [_model currentVideoResoultionConstraintFromStore];
+  NSString *string = [_model currentVideoResolutionSettingFromStore];
 
   XCTAssertEqualObjects(string, @"640x480");
   [storeMock verify];
 }
 
 - (void)testStoringInvalidConstraintReturnsNo {
-  __unused id storeMock = [self setupMockStoreWithMediaConstraintString:@"960x480"];
-  XCTAssertFalse([_model storeVideoResoultionConstraint:@"960x480"]);
+  __unused id storeMock = [self setupMockStoreWithVideoResolution:@"960x480"];
+  XCTAssertFalse([_model storeVideoResolutionSetting:@"960x480"]);
 }
 
 - (void)testWidthConstraintFromStore {
-  [self setupMockStoreWithMediaConstraintString:@"1270x480"];
-  NSString *width = [_model currentVideoResolutionWidthFromStore];
+  [self setupMockStoreWithVideoResolution:@"1270x480"];
+  int width = [_model currentVideoResolutionWidthFromStore];
 
-  XCTAssertEqualObjects(width, @"1270");
+  XCTAssertEqual(width, 1270);
 }
 
 - (void)testHeightConstraintFromStore {
-  [self setupMockStoreWithMediaConstraintString:@"960x540"];
-  NSString *height = [_model currentVideoResolutionHeightFromStore];
+  [self setupMockStoreWithVideoResolution:@"960x540"];
+  int height = [_model currentVideoResolutionHeightFromStore];
 
-  XCTAssertEqualObjects(height, @"540");
+  XCTAssertEqual(height, 540);
 }
 
 - (void)testConstraintComponentIsNilWhenInvalidConstraintString {
-  [self setupMockStoreWithMediaConstraintString:@"invalid"];
-  NSString *width = [_model currentVideoResolutionWidthFromStore];
+  [self setupMockStoreWithVideoResolution:@"invalid"];
+  int width = [_model currentVideoResolutionWidthFromStore];
 
-  XCTAssertNil(width);
-}
-
-- (void)testConstraintsDictionaryIsNilWhenInvalidConstraintString {
-  [self setupMockStoreWithMediaConstraintString:@"invalid"];
-  NSDictionary *constraintsDictionary = [_model currentMediaConstraintFromStoreAsRTCDictionary];
-
-  XCTAssertNil(constraintsDictionary);
+  XCTAssertEqual(width, 0);
 }
 @end