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}
This commit is contained in:
@ -60,7 +60,8 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) {
|
||||
@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;
|
||||
|
||||
@ -100,6 +100,7 @@ static int const kKbpsMultiplier = 1000;
|
||||
ARDTimerProxy *_statsTimer;
|
||||
RTCMediaConstraints *_cameraConstraints;
|
||||
NSNumber *_maxBitrate;
|
||||
NSString *_videoCodec;
|
||||
}
|
||||
|
||||
@synthesize shouldGetStats = _shouldGetStats;
|
||||
@ -128,13 +129,15 @@ static int const kKbpsMultiplier = 1000;
|
||||
@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 @@ static int const kKbpsMultiplier = 1000;
|
||||
[_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 @@ static int const kKbpsMultiplier = 1000;
|
||||
}];
|
||||
ARDSessionDescriptionMessage *message =
|
||||
[[ARDSessionDescriptionMessage alloc]
|
||||
initWithDescription:sdpPreferringH264];
|
||||
initWithDescription:sdpPreferringCodec];
|
||||
[self sendSignalingMessage:message];
|
||||
[self setMaxBitrateForPeerConnectionVideoSender];
|
||||
});
|
||||
@ -606,12 +609,12 @@ static int const kKbpsMultiplier = 1000;
|
||||
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
|
||||
|
||||
@ -48,6 +48,26 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (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.
|
||||
|
||||
@ -17,6 +17,10 @@ static NSArray<NSString *> *videoResolutionsStaticValues() {
|
||||
return @[ @"640x480", @"960x540", @"1280x720" ];
|
||||
}
|
||||
|
||||
static NSArray<NSString *> *videoCodecsStaticValues() {
|
||||
return @[ @"H264", @"VP8", @"VP9" ];
|
||||
}
|
||||
|
||||
@interface ARDSettingsModel () {
|
||||
ARDSettingsStore *_settingsStore;
|
||||
}
|
||||
@ -46,6 +50,27 @@ static NSArray<NSString *> *videoResolutionsStaticValues() {
|
||||
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 @@ static NSArray<NSString *> *videoResolutionsStaticValues() {
|
||||
return components[index];
|
||||
}
|
||||
|
||||
- (NSString *)defaultVideoCodecSetting {
|
||||
return videoCodecsStaticValues()[0];
|
||||
}
|
||||
|
||||
#pragma mark - Conversion to RTCMediaConstraints
|
||||
|
||||
- (nullable NSDictionary *)currentMediaConstraintFromStoreAsRTCDictionary {
|
||||
|
||||
@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface ARDSettingsStore : NSObject
|
||||
|
||||
@property(nonatomic) NSString* videoCodec;
|
||||
|
||||
/**
|
||||
* Returns current video resolution media constraint string stored in the store.
|
||||
*/
|
||||
|
||||
@ -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 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[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];
|
||||
}
|
||||
|
||||
@ -15,7 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
ARDSettingsSectionMediaConstraints = 0,
|
||||
ARDSettingsSectionBitRate
|
||||
ARDSettingsSectionVideoCodec,
|
||||
ARDSettingsSectionBitRate,
|
||||
};
|
||||
|
||||
@interface ARDSettingsViewController () <UITextFieldDelegate> {
|
||||
@ -43,9 +44,18 @@ typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
[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 @@ typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
return _settingsModel.availableVideoResoultionsMediaConstraints;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)videoCodecArray {
|
||||
return _settingsModel.availableVideoCodecs;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)addDoneBarButton {
|
||||
@ -64,16 +78,14 @@ typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
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 @@ typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
#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 @@ typedef NS_ENUM(int, ARDSettingsSections) {
|
||||
|
||||
- (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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -369,7 +369,8 @@ static NSUInteger const kBottomViewHeight = 200;
|
||||
}
|
||||
|
||||
[_client disconnect];
|
||||
ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self];
|
||||
ARDAppClient *client = [[ARDAppClient alloc] initWithDelegate:self
|
||||
preferVideoCodec:@"H264"];
|
||||
[client connectToRoomWithId:roomId
|
||||
isLoopback:isLoopback
|
||||
isAudioOnly:NO
|
||||
|
||||
Reference in New Issue
Block a user