Add video codec setting to AppRTCMobile on iOS.

List items in settings menu no longer stay selected. Checkmarks are now
added to the selected options before the view appears.

BUG=webrtc:7316
TBR=denicija

Review-Url: https://codereview.webrtc.org/2735303004
Cr-Commit-Position: refs/heads/master@{#17296}
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
index 60ef700..0feb015 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
+++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h
@@ -60,7 +60,8 @@
 @property(nonatomic, weak) id<ARDAppClientDelegate> delegate;
 // Convenience constructor since all expected use cases will need a delegate
 // in order to receive remote tracks.
-- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate;
+- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate
+                preferVideoCodec:(NSString*)codec;
 
 // Sets camera constraints.
 - (void)setCameraConstraints:(RTCMediaConstraints *)mediaConstraints;
diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
index ef21ab6..497a137 100644
--- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
+++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m
@@ -100,6 +100,7 @@
   ARDTimerProxy *_statsTimer;
   RTCMediaConstraints *_cameraConstraints;
   NSNumber *_maxBitrate;
+  NSString *_videoCodec;
 }
 
 @synthesize shouldGetStats = _shouldGetStats;
@@ -128,13 +129,15 @@
 @synthesize shouldUseLevelControl = _shouldUseLevelControl;
 
 - (instancetype)init {
-  return [self initWithDelegate:nil];
+  return [self initWithDelegate:nil preferVideoCodec:@"H264"];
 }
 
-- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate {
+- (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate
+                preferVideoCodec:(NSString *)codec {
   if (self = [super init]) {
     _roomServerClient = [[ARDAppEngineClient alloc] init];
     _delegate = delegate;
+    _videoCodec = codec;
     NSURL *turnRequestURL = [NSURL URLWithString:kARDIceServerRequestUrl];
     _turnClient = [[ARDTURNClient alloc] initWithURL:turnRequestURL];
     [self configure];
@@ -452,12 +455,12 @@
       [_delegate appClient:self didError:sdpError];
       return;
     }
-    // Prefer H264 if available.
-    RTCSessionDescription *sdpPreferringH264 =
+    // Prefer codec from settings if available.
+    RTCSessionDescription *sdpPreferringCodec =
         [ARDSDPUtils descriptionForDescription:sdp
-                           preferredVideoCodec:@"H264"];
+                           preferredVideoCodec:_videoCodec];
     __weak ARDAppClient *weakSelf = self;
-    [_peerConnection setLocalDescription:sdpPreferringH264
+    [_peerConnection setLocalDescription:sdpPreferringCodec
                        completionHandler:^(NSError *error) {
       ARDAppClient *strongSelf = weakSelf;
       [strongSelf peerConnection:strongSelf.peerConnection
@@ -465,7 +468,7 @@
     }];
     ARDSessionDescriptionMessage *message =
         [[ARDSessionDescriptionMessage alloc]
-            initWithDescription:sdpPreferringH264];
+            initWithDescription:sdpPreferringCodec];
     [self sendSignalingMessage:message];
     [self setMaxBitrateForPeerConnectionVideoSender];
   });
@@ -606,12 +609,12 @@
       ARDSessionDescriptionMessage *sdpMessage =
           (ARDSessionDescriptionMessage *)message;
       RTCSessionDescription *description = sdpMessage.sessionDescription;
-      // Prefer H264 if available.
-      RTCSessionDescription *sdpPreferringH264 =
+      // Prefer codec from settings if available.
+      RTCSessionDescription *sdpPreferringCodec =
           [ARDSDPUtils descriptionForDescription:description
-                             preferredVideoCodec:@"H264"];
+                             preferredVideoCodec:_videoCodec];
       __weak ARDAppClient *weakSelf = self;
-      [_peerConnection setRemoteDescription:sdpPreferringH264
+      [_peerConnection setRemoteDescription:sdpPreferringCodec
                           completionHandler:^(NSError *error) {
         ARDAppClient *strongSelf = weakSelf;
         [strongSelf peerConnection:strongSelf.peerConnection
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.h b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.h
index 602a464..0eb7b31 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.h
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.h
@@ -49,6 +49,26 @@
 - (BOOL)storeVideoResoultionConstraint:(NSString *)constraint;
 
 /**
+ * Returns array of available video codecs.
+ */
+- (NSArray<NSString *> *)availableVideoCodecs;
+
+/**
+ * Returns current video codec setting from store if present.
+ */
+- (NSString *)currentVideoCodecSettingFromStore;
+
+/**
+ * Stores the provided video codec setting into the store.
+ *
+ * If the provided constraint 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.
+ */
+- (BOOL)storeVideoCodecSetting:(NSString *)videoCodec;
+
+/**
  * Converts the current media constraints from store into dictionary with RTCMediaConstraints
  * values.
  *
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.m
index eda0275..7514689 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsModel.m
@@ -17,6 +17,10 @@
   return @[ @"640x480", @"960x540", @"1280x720" ];
 }
 
+static NSArray<NSString *> *videoCodecsStaticValues() {
+  return @[ @"H264", @"VP8", @"VP9" ];
+}
+
 @interface ARDSettingsModel () {
   ARDSettingsStore *_settingsStore;
 }
@@ -46,6 +50,27 @@
   return YES;
 }
 
+- (NSArray<NSString *> *)availableVideoCodecs {
+  return videoCodecsStaticValues();
+}
+
+- (NSString *)currentVideoCodecSettingFromStore {
+  NSString *videoCodec = [[self settingsStore] videoCodec];
+  if (!videoCodec) {
+    videoCodec = [self defaultVideoCodecSetting];
+    [[self settingsStore] setVideoCodec:videoCodec];
+  }
+  return videoCodec;
+}
+
+- (BOOL)storeVideoCodecSetting:(NSString *)videoCodec {
+  if (![[self availableVideoCodecs] containsObject:videoCodec]) {
+    return NO;
+  }
+  [[self settingsStore] setVideoCodec:videoCodec];
+  return YES;
+}
+
 - (nullable NSNumber *)currentMaxBitrateSettingFromStore {
   return [[self settingsStore] maxBitrate];
 }
@@ -92,6 +117,10 @@
   return components[index];
 }
 
+- (NSString *)defaultVideoCodecSetting {
+  return videoCodecsStaticValues()[0];
+}
+
 #pragma mark - Conversion to RTCMediaConstraints
 
 - (nullable NSDictionary *)currentMediaConstraintFromStoreAsRTCDictionary {
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.h b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.h
index 69e10e3..b82ec70 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.h
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.h
@@ -19,6 +19,8 @@
  */
 @interface ARDSettingsStore : NSObject
 
+@property(nonatomic) NSString* videoCodec;
+
 /**
  * Returns current video resolution media constraint string stored in the store.
  */
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.m
index fd396b5..c05df44 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsStore.m
@@ -11,6 +11,7 @@
 #import "ARDSettingsStore.h"
 
 static NSString *const kMediaConstraintsKey = @"rtc_video_resolution_media_constraints_key";
+static NSString *const kVideoCodecKey = @"rtc_video_codec_key";
 static NSString *const kBitrateKey = @"rtc_max_bitrate_key";
 
 NS_ASSUME_NONNULL_BEGIN
@@ -38,6 +39,15 @@
   [self.storage synchronize];
 }
 
+- (NSString *)videoCodec {
+  return [self.storage objectForKey:kVideoCodecKey];
+}
+
+- (void)setVideoCodec:(NSString *)videoCodec {
+  [self.storage setObject:videoCodec forKey:kVideoCodecKey];
+  [self.storage synchronize];
+}
+
 - (nullable NSNumber *)maxBitrate {
   return [self.storage objectForKey:kBitrateKey];
 }
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
index 815b147..fb59dd2 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m
@@ -15,7 +15,8 @@
 
 typedef NS_ENUM(int, ARDSettingsSections) {
   ARDSettingsSectionMediaConstraints = 0,
-  ARDSettingsSectionBitRate
+  ARDSettingsSectionVideoCodec,
+  ARDSettingsSectionBitRate,
 };
 
 @interface ARDSettingsViewController () <UITextFieldDelegate> {
@@ -43,9 +44,18 @@
   [self addDoneBarButton];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+  [self addCheckmarkInSection:ARDSettingsSectionMediaConstraints
+                    withArray:[self mediaConstraintsArray]
+                    selecting:[_settingsModel currentVideoResoultionConstraintFromStore]];
+  [self addCheckmarkInSection:ARDSettingsSectionVideoCodec
+                    withArray:[self videoCodecArray]
+                    selecting:[_settingsModel currentVideoCodecSettingFromStore]];
+}
+
 - (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
-  [self selectCurrentlyStoredOrDefaultMediaConstraints];
 }
 
 #pragma mark - Data source
@@ -54,6 +64,10 @@
   return _settingsModel.availableVideoResoultionsMediaConstraints;
 }
 
+- (NSArray<NSString *> *)videoCodecArray {
+  return _settingsModel.availableVideoCodecs;
+}
+
 #pragma mark -
 
 - (void)addDoneBarButton {
@@ -64,16 +78,14 @@
   self.navigationItem.leftBarButtonItem = barItem;
 }
 
-- (void)selectCurrentlyStoredOrDefaultMediaConstraints {
-  NSString *currentSelection = [_settingsModel currentVideoResoultionConstraintFromStore];
-
-  NSUInteger indexOfSelection = [[self mediaConstraintsArray] indexOfObject:currentSelection];
-  NSIndexPath *pathToBeSelected = [NSIndexPath indexPathForRow:indexOfSelection inSection:0];
-  [self.tableView selectRowAtIndexPath:pathToBeSelected
-                              animated:NO
-                        scrollPosition:UITableViewScrollPositionNone];
-  // Manully invoke the delegate method because the previous invocation will not.
-  [self tableView:self.tableView didSelectRowAtIndexPath:pathToBeSelected];
+- (void)addCheckmarkInSection:(int)section
+                    withArray:(NSArray<NSString*>*) array
+                    selecting:(NSString*)selection {
+  NSUInteger indexOfSelection = [array indexOfObject:selection];
+  NSIndexPath *pathToBeDecorated = [NSIndexPath indexPathForRow:indexOfSelection
+                                                      inSection:section];
+  UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:pathToBeDecorated];
+  cell.accessoryType = UITableViewCellAccessoryCheckmark;
 }
 
 #pragma mark - Dismissal of view controller
@@ -85,75 +97,84 @@
 #pragma mark - Table view data source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
-  return 2;
+  return 3;
 }
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
-  if ([self sectionIsMediaConstraints:section]) {
-    return self.mediaConstraintsArray.count;
+  switch (section) {
+    case ARDSettingsSectionMediaConstraints:
+      return self.mediaConstraintsArray.count;
+    case ARDSettingsSectionVideoCodec:
+      return self.videoCodecArray.count;
+    default:
+      return 1;
   }
-
-  return 1;
 }
 
-#pragma mark - Index path helpers
+#pragma mark - Table view delegate helpers
 
-- (BOOL)sectionIsMediaConstraints:(int)section {
-  return section == ARDSettingsSectionMediaConstraints;
+- (void)removeAllAccessories:(UITableView *)tableView
+                   inSection:(int)section
+{
+  for (int i = 0; i < [tableView numberOfRowsInSection:section]; i++) {
+    NSIndexPath *rowPath = [NSIndexPath indexPathForRow:i inSection:section];
+    UITableViewCell *cell = [tableView cellForRowAtIndexPath:rowPath];
+    cell.accessoryType = UITableViewCellAccessoryNone;
+  }
 }
 
-- (BOOL)sectionIsBitrate:(int)section {
-  return section == ARDSettingsSectionBitRate;
-}
-
-- (BOOL)indexPathIsMediaConstraints:(NSIndexPath *)indexPath {
-  return [self sectionIsMediaConstraints:indexPath.section];
-}
-
-- (BOOL)indexPathIsBitrate:(NSIndexPath *)indexPath {
-  return [self sectionIsBitrate:indexPath.section];
+- (void)tableView:(UITableView *)tableView
+updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
+        inSection:(int)section {
+  [self removeAllAccessories:tableView inSection:section];
+  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+  cell.accessoryType = UITableViewCellAccessoryCheckmark;
+  [tableView deselectRowAtIndexPath:indexPath animated:YES];
 }
 
 #pragma mark - Table view delegate
 
 - (nullable NSString *)tableView:(UITableView *)tableView
          titleForHeaderInSection:(NSInteger)section {
-  if ([self sectionIsMediaConstraints:section]) {
-    return @"Media constraints";
+  switch (section) {
+    case ARDSettingsSectionMediaConstraints:
+      return @"Media constraints";
+    case ARDSettingsSectionVideoCodec:
+      return @"Video codec";
+    case ARDSettingsSectionBitRate:
+      return @"Maximum bitrate";
+    default:
+      return @"";
   }
-
-  if ([self sectionIsBitrate:section]) {
-    return @"Maximum bitrate";
-  }
-
-  return @"";
 }
 
 - (UITableViewCell *)tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-  if ([self indexPathIsMediaConstraints:indexPath]) {
-    return [self mediaConstraintsTableViewCellForTableView:tableView atIndexPath:indexPath];
-  }
+  switch (indexPath.section) {
+    case ARDSettingsSectionMediaConstraints:
+      return [self mediaConstraintsTableViewCellForTableView:tableView atIndexPath:indexPath];
 
-  if ([self indexPathIsBitrate:indexPath]) {
-    return [self bitrateTableViewCellForTableView:tableView atIndexPath:indexPath];
-  }
+    case ARDSettingsSectionVideoCodec:
+      return [self videoCodecTableViewCellForTableView:tableView atIndexPath:indexPath];
 
-  return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
-                                reuseIdentifier:@"identifier"];
-}
+    case ARDSettingsSectionBitRate:
+      return [self bitrateTableViewCellForTableView:tableView atIndexPath:indexPath];
 
-- (nullable NSIndexPath *)tableView:(UITableView *)tableView
-           willSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
-  if ([self indexPathIsMediaConstraints:indexPath]) {
-    return [self tableView:tableView willDeselectMediaConstraintsRowAtIndexPath:indexPath];
+    default:
+      return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
+                                    reuseIdentifier:@"identifier"];
   }
-  return indexPath;
 }
 
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
-  if ([self indexPathIsMediaConstraints:indexPath]) {
-    [self tableView:tableView didSelectMediaConstraintsCellAtIndexPath:indexPath];
+  switch (indexPath.section) {
+    case ARDSettingsSectionMediaConstraints:
+      [self tableView:tableView didSelectMediaConstraintsCellAtIndexPath:indexPath];
+      break;
+
+    case ARDSettingsSectionVideoCodec:
+      [self tableView:tableView didSelectVideoCodecCellAtIndexPath:indexPath];
+      break;
   }
 }
 
@@ -173,19 +194,37 @@
 
 - (void)tableView:(UITableView *)tableView
     didSelectMediaConstraintsCellAtIndexPath:(NSIndexPath *)indexPath {
-  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
-  cell.accessoryType = UITableViewCellAccessoryCheckmark;
+  [self tableView:tableView
+    updateListSelectionAtIndexPath:indexPath
+        inSection:ARDSettingsSectionMediaConstraints];
 
   NSString *mediaConstraintsString = self.mediaConstraintsArray[indexPath.row];
   [_settingsModel storeVideoResoultionConstraint:mediaConstraintsString];
 }
 
-- (NSIndexPath *)tableView:(UITableView *)tableView
-    willDeselectMediaConstraintsRowAtIndexPath:(NSIndexPath *)indexPath {
-  NSIndexPath *oldSelection = [tableView indexPathForSelectedRow];
-  UITableViewCell *cell = [tableView cellForRowAtIndexPath:oldSelection];
-  cell.accessoryType = UITableViewCellAccessoryNone;
-  return indexPath;
+#pragma mark - Table view delegate(Video Codec)
+
+- (UITableViewCell *)videoCodecTableViewCellForTableView:(UITableView *)tableView
+                                             atIndexPath:(NSIndexPath *)indexPath {
+  NSString *dequeueIdentifier = @"ARDSettingsVideoCodecCellIdentifier";
+  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier];
+  if (!cell) {
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
+                                  reuseIdentifier:dequeueIdentifier];
+  }
+  cell.textLabel.text = self.videoCodecArray[indexPath.row];
+
+  return cell;
+}
+
+- (void)tableView:(UITableView *)tableView
+    didSelectVideoCodecCellAtIndexPath:(NSIndexPath *)indexPath {
+  [self tableView:tableView
+    updateListSelectionAtIndexPath:indexPath
+        inSection:ARDSettingsSectionVideoCodec];
+
+  NSString *videoCodec = self.videoCodecArray[indexPath.row];
+  [_settingsModel storeVideoCodecSetting:videoCodec];
 }
 
 #pragma mark - Table view delegate(Bitrate)
diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
index 9e17951..f58ee66 100644
--- a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m
@@ -44,9 +44,11 @@
       shouldUseLevelControl:(BOOL)shouldUseLevelControl
                    delegate:(id<ARDVideoCallViewControllerDelegate>)delegate {
   if (self = [super init]) {
-    _delegate = delegate;
-    _client = [[ARDAppClient alloc] initWithDelegate:self];
     ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
+    NSString* videoCodec = [settingsModel currentVideoCodecSettingFromStore];
+    _delegate = delegate;
+    _client = [[ARDAppClient alloc] initWithDelegate:self
+                                    preferVideoCodec:videoCodec];
     RTCMediaConstraints *cameraConstraints = [[RTCMediaConstraints alloc]
         initWithMandatoryConstraints:nil
                  optionalConstraints:[settingsModel
diff --git a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
index 176ea19..bcf26b2 100644
--- a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
+++ b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m
@@ -369,7 +369,8 @@
   }
 
   [_client disconnect];
-  ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self];
+  ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self
+                                               preferVideoCodec:@"H264"];
   [client connectToRoomWithId:roomId
                    isLoopback:isLoopback
                   isAudioOnly:NO