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