Move setting switches in AppRTCMobile to Settings screen

All setting switches except "Loopback mode" is now in the Settings
screen instead of the main screen. They are also persisted across app
launches.

Bug: webrtc:7748
Change-Id: Iafd84e5e39639770118e2503148d1bf7fb9c3d8d
Reviewed-on: https://chromium-review.googlesource.com/527034
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#18626}
This commit is contained in:
Anders Carlsson
2017-06-15 16:05:13 +02:00
committed by Commit Bot
parent 7c303907a4
commit e150058236
16 changed files with 350 additions and 246 deletions

View File

@ -42,9 +42,6 @@
@property(nonatomic, strong) NSURL *webSocketURL;
@property(nonatomic, strong) NSURL *webSocketRestURL;
@property(nonatomic, readonly) BOOL isLoopback;
@property(nonatomic, readonly) BOOL isAudioOnly;
@property(nonatomic, readonly) BOOL shouldMakeAecDump;
@property(nonatomic, readonly) BOOL shouldUseLevelControl;
@property(nonatomic, strong)
RTCMediaConstraints *defaultPeerConnectionConstraints;

View File

@ -70,16 +70,9 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) {
// Establishes a connection with the AppRTC servers for the given room id.
// |settings| is an object containing settings such as video codec for the call.
// If |isLoopback| is true, the call will connect to itself.
// If |isAudioOnly| is true, video will be disabled for the call.
// If |shouldMakeAecDump| is true, an aecdump will be created for the call.
// If |shouldUseLevelControl| is true, the level controller will be used
// in the call.
- (void)connectToRoomWithId:(NSString *)roomId
settings:(ARDSettingsModel *)settings
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl;
isLoopback:(BOOL)isLoopback;
// Disconnects from the AppRTC servers and any connected clients.
- (void)disconnect;

View File

@ -126,9 +126,6 @@ static int const kKbpsMultiplier = 1000;
@synthesize defaultPeerConnectionConstraints =
_defaultPeerConnectionConstraints;
@synthesize isLoopback = _isLoopback;
@synthesize isAudioOnly = _isAudioOnly;
@synthesize shouldMakeAecDump = _shouldMakeAecDump;
@synthesize shouldUseLevelControl = _shouldUseLevelControl;
- (instancetype)init {
return [self initWithDelegate:nil];
@ -214,17 +211,11 @@ static int const kKbpsMultiplier = 1000;
- (void)connectToRoomWithId:(NSString *)roomId
settings:(ARDSettingsModel *)settings
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl {
isLoopback:(BOOL)isLoopback {
NSParameterAssert(roomId.length);
NSParameterAssert(_state == kARDAppClientStateDisconnected);
_settings = settings;
_isLoopback = isLoopback;
_isAudioOnly = isAudioOnly;
_shouldMakeAecDump = shouldMakeAecDump;
_shouldUseLevelControl = shouldUseLevelControl;
self.state = kARDAppClientStateConnecting;
#if defined(WEBRTC_IOS)
@ -569,7 +560,7 @@ static int const kKbpsMultiplier = 1000;
}
// Start aecdump diagnostic recording.
if (_shouldMakeAecDump) {
if ([_settings currentCreateAecDumpSettingFromStore]) {
NSString *filePath = [self documentsFilePathForFileName:@"webrtc-audio.aecdump"];
if (![_factory startAecDumpWithFilePath:filePath
maxSizeInBytes:kARDAppClientAecDumpMaxSizeInBytes]) {
@ -719,7 +710,7 @@ static int const kKbpsMultiplier = 1000;
// support or emulation (http://goo.gl/rHAnC1) so don't bother
// trying to open a local stream.
#if !TARGET_IPHONE_SIMULATOR
if (!_isAudioOnly) {
if (![_settings currentAudioOnlySettingFromStore]) {
RTCVideoSource *source = [_factory videoSource];
RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source];
[_delegate appClient:self didCreateLocalCapturer:capturer];
@ -758,8 +749,9 @@ static int const kKbpsMultiplier = 1000;
#pragma mark - Defaults
- (RTCMediaConstraints *)defaultMediaAudioConstraints {
NSString *valueLevelControl = _shouldUseLevelControl ?
kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse;
NSString *valueLevelControl = [_settings currentUseLevelControllerSettingFromStore] ?
kRTCMediaConstraintsValueTrue :
kRTCMediaConstraintsValueFalse;
NSDictionary *mandatoryConstraints = @{ kRTCMediaConstraintsLevelControl : valueLevelControl };
RTCMediaConstraints *constraints =
[[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints

View File

@ -11,6 +11,7 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Model class for user defined settings.
*
@ -79,5 +80,55 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate;
/**
* Returns current audio only setting from store if present or default (NO) otherwise.
*/
- (BOOL)currentAudioOnlySettingFromStore;
/**
* Stores the provided audio only setting into the store.
*
* @param setting the boolean value to be stored.
*/
- (void)storeAudioOnlySetting:(BOOL)audioOnly;
/**
* Returns current create AecDump setting from store if present or default (NO) otherwise.
*/
- (BOOL)currentCreateAecDumpSettingFromStore;
/**
* Stores the provided create AecDump setting into the store.
*
* @param setting the boolean value to be stored.
*/
- (void)storeCreateAecDumpSetting:(BOOL)createAecDump;
/**
* Returns current setting whether to use level controller from store if present or default (NO)
* otherwise.
*/
- (BOOL)currentUseLevelControllerSettingFromStore;
/**
* Stores the provided use level controller setting into the store.
*
* @param setting the boolean value to be stored.
*/
- (void)storeUseLevelControllerSetting:(BOOL)useLevelController;
/**
* Returns current setting whether to use manual audio config from store if present or default (YES)
* otherwise.
*/
- (BOOL)currentUseManualAudioConfigSettingFromStore;
/**
* Stores the provided use manual audio config setting into the store.
*
* @param setting the boolean value to be stored.
*/
- (void)storeUseManualAudioConfigSetting:(BOOL)useManualAudioConfig;
@end
NS_ASSUME_NONNULL_END

View File

@ -56,13 +56,8 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
}
- (NSString *)currentVideoResolutionSettingFromStore {
NSString *resolution = [[self settingsStore] videoResolution];
if (!resolution) {
resolution = [self defaultVideoResolutionSetting];
// To ensure consistency add the default to the store.
[[self settingsStore] setVideoResolution:resolution];
}
return resolution;
[self registerStoreDefaults];
return [[self settingsStore] videoResolution];
}
- (BOOL)storeVideoResolutionSetting:(NSString *)resolution {
@ -78,12 +73,8 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
}
- (NSString *)currentVideoCodecSettingFromStore {
NSString *videoCodec = [[self settingsStore] videoCodec];
if (!videoCodec) {
videoCodec = [self defaultVideoCodecSetting];
[[self settingsStore] setVideoCodec:videoCodec];
}
return videoCodec;
[self registerStoreDefaults];
return [[self settingsStore] videoCodec];
}
- (BOOL)storeVideoCodecSetting:(NSString *)videoCodec {
@ -95,6 +86,7 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
}
- (nullable NSNumber *)currentMaxBitrateSettingFromStore {
[self registerStoreDefaults];
return [[self settingsStore] maxBitrate];
}
@ -102,11 +94,44 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
[[self settingsStore] setMaxBitrate:bitrate];
}
- (BOOL)currentAudioOnlySettingFromStore {
return [[self settingsStore] audioOnly];
}
- (void)storeAudioOnlySetting:(BOOL)audioOnly {
[[self settingsStore] setAudioOnly:audioOnly];
}
- (BOOL)currentCreateAecDumpSettingFromStore {
return [[self settingsStore] createAecDump];
}
- (void)storeCreateAecDumpSetting:(BOOL)createAecDump {
[[self settingsStore] setCreateAecDump:createAecDump];
}
- (BOOL)currentUseLevelControllerSettingFromStore {
return [[self settingsStore] useLevelController];
}
- (void)storeUseLevelControllerSetting:(BOOL)useLevelController {
[[self settingsStore] setUseLevelController:useLevelController];
}
- (BOOL)currentUseManualAudioConfigSettingFromStore {
return [[self settingsStore] useManualAudioConfig];
}
- (void)storeUseManualAudioConfigSetting:(BOOL)useManualAudioConfig {
[[self settingsStore] setUseManualAudioConfig:useManualAudioConfig];
}
#pragma mark - Testable
- (ARDSettingsStore *)settingsStore {
if (!_settingsStore) {
_settingsStore = [[ARDSettingsStore alloc] init];
[self registerStoreDefaults];
}
return _settingsStore;
}
@ -128,6 +153,10 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
return [self availableVideoResolutions][0];
}
- (NSString *)defaultVideoCodecSetting {
return videoCodecsStaticValues()[0];
}
- (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolution {
if (index != 0 && index != 1) {
return 0;
@ -139,8 +168,14 @@ static NSArray<NSString *> *videoCodecsStaticValues() {
return components[index].intValue;
}
- (NSString *)defaultVideoCodecSetting {
return videoCodecsStaticValues()[0];
- (void)registerStoreDefaults {
[ARDSettingsStore setDefaultsForVideoResolution:[self defaultVideoResolutionSetting]
videoCodec:[self defaultVideoCodecSetting]
bitrate:nil
audioOnly:NO
createAecDump:NO
useLevelController:NO
useManualAudioConfig:YES];
}
@end

View File

@ -19,6 +19,18 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface ARDSettingsStore : NSObject
/**
* Set fallback values in case the setting has not been written by the user.
* @param dictionary of values to store
*/
+ (void)setDefaultsForVideoResolution:(NSString *)videoResolution
videoCodec:(NSString *)videoCodec
bitrate:(nullable NSNumber *)bitrate
audioOnly:(BOOL)audioOnly
createAecDump:(BOOL)createAecDump
useLevelController:(BOOL)useLevelController
useManualAudioConfig:(BOOL)useManualAudioConfig;
@property(nonatomic) NSString *videoResolution;
@property(nonatomic) NSString *videoCodec;
@ -33,5 +45,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)setMaxBitrate:(nullable NSNumber *)value;
@property(nonatomic) BOOL audioOnly;
@property(nonatomic) BOOL createAecDump;
@property(nonatomic) BOOL useLevelController;
@property(nonatomic) BOOL useManualAudioConfig;
@end
NS_ASSUME_NONNULL_END

View File

@ -13,6 +13,10 @@
static NSString *const kVideoResolutionKey = @"rtc_video_resolution_key";
static NSString *const kVideoCodecKey = @"rtc_video_codec_key";
static NSString *const kBitrateKey = @"rtc_max_bitrate_key";
static NSString *const kAudioOnlyKey = @"rtc_audio_only_key";
static NSString *const kCreateAecDumpKey = @"rtc_create_aec_dump_key";
static NSString *const kUseLevelControllerKey = @"rtc_use_level_controller_key";
static NSString *const kUseManualAudioConfigKey = @"rtc_use_manual_audio_config_key";
NS_ASSUME_NONNULL_BEGIN
@interface ARDSettingsStore () {
@ -23,6 +27,27 @@ NS_ASSUME_NONNULL_BEGIN
@implementation ARDSettingsStore
+ (void)setDefaultsForVideoResolution:(NSString *)videoResolution
videoCodec:(NSString *)videoCodec
bitrate:(nullable NSNumber *)bitrate
audioOnly:(BOOL)audioOnly
createAecDump:(BOOL)createAecDump
useLevelController:(BOOL)useLevelController
useManualAudioConfig:(BOOL)useManualAudioConfig {
NSMutableDictionary<NSString *, id> *defaultsDictionary = [@{
kVideoResolutionKey : videoResolution,
kVideoCodecKey : videoCodec,
kAudioOnlyKey : @(audioOnly),
kCreateAecDumpKey : @(createAecDump),
kUseLevelControllerKey : @(useLevelController),
kUseManualAudioConfigKey : @(useManualAudioConfig)
} mutableCopy];
if (bitrate) {
[defaultsDictionary setObject:bitrate forKey:kBitrateKey];
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
}
- (NSUserDefaults *)storage {
if (!_storage) {
_storage = [NSUserDefaults standardUserDefaults];
@ -57,5 +82,41 @@ NS_ASSUME_NONNULL_BEGIN
[self.storage synchronize];
}
- (BOOL)audioOnly {
return [self.storage boolForKey:kAudioOnlyKey];
}
- (void)setAudioOnly:(BOOL)audioOnly {
[self.storage setBool:audioOnly forKey:kAudioOnlyKey];
[self.storage synchronize];
}
- (BOOL)createAecDump {
return [self.storage boolForKey:kCreateAecDumpKey];
}
- (void)setCreateAecDump:(BOOL)createAecDump {
[self.storage setBool:createAecDump forKey:kCreateAecDumpKey];
[self.storage synchronize];
}
- (BOOL)useLevelController {
return [self.storage boolForKey:kUseLevelControllerKey];
}
- (void)setUseLevelController:(BOOL)useLevelController {
[self.storage setBool:useLevelController forKey:kUseLevelControllerKey];
[self.storage synchronize];
}
- (BOOL)useManualAudioConfig {
return [self.storage boolForKey:kUseManualAudioConfigKey];
}
- (void)setUseManualAudioConfig:(BOOL)useManualAudioConfig {
[self.storage setBool:useManualAudioConfig forKey:kUseManualAudioConfigKey];
[self.storage synchronize];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -14,14 +14,7 @@
@protocol ARDMainViewDelegate <NSObject>
- (void)mainView:(ARDMainView *)mainView
didInputRoom:(NSString *)room
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl
useManualAudio:(BOOL)useManualAudio;
- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback;
- (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView;
@end

View File

@ -74,16 +74,8 @@ static CGFloat const kCallControlMargin = 8;
@implementation ARDMainView {
ARDRoomTextField *_roomText;
UILabel *_callOptionsLabel;
UISwitch *_audioOnlySwitch;
UILabel *_audioOnlyLabel;
UISwitch *_aecdumpSwitch;
UILabel *_aecdumpLabel;
UISwitch *_levelControlSwitch;
UILabel *_levelControlLabel;
UISwitch *_loopbackSwitch;
UILabel *_loopbackLabel;
UISwitch *_useManualAudioSwitch;
UILabel *_useManualAudioLabel;
UIButton *_startCallButton;
UIButton *_audioLoopButton;
}
@ -106,17 +98,6 @@ static CGFloat const kCallControlMargin = 8;
[_callOptionsLabel sizeToFit];
[self addSubview:_callOptionsLabel];
_audioOnlySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[_audioOnlySwitch sizeToFit];
[self addSubview:_audioOnlySwitch];
_audioOnlyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_audioOnlyLabel.text = @"Audio only";
_audioOnlyLabel.font = controlFont;
_audioOnlyLabel.textColor = controlFontColor;
[_audioOnlyLabel sizeToFit];
[self addSubview:_audioOnlyLabel];
_loopbackSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[_loopbackSwitch sizeToFit];
[self addSubview:_loopbackSwitch];
@ -128,40 +109,6 @@ static CGFloat const kCallControlMargin = 8;
[_loopbackLabel sizeToFit];
[self addSubview:_loopbackLabel];
_aecdumpSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[_aecdumpSwitch sizeToFit];
[self addSubview:_aecdumpSwitch];
_aecdumpLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_aecdumpLabel.text = @"Create AecDump";
_aecdumpLabel.font = controlFont;
_aecdumpLabel.textColor = controlFontColor;
[_aecdumpLabel sizeToFit];
[self addSubview:_aecdumpLabel];
_levelControlSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[_levelControlSwitch sizeToFit];
[self addSubview:_levelControlSwitch];
_levelControlLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_levelControlLabel.text = @"Use level controller";
_levelControlLabel.font = controlFont;
_levelControlLabel.textColor = controlFontColor;
[_levelControlLabel sizeToFit];
[self addSubview:_levelControlLabel];
_useManualAudioSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
[_useManualAudioSwitch sizeToFit];
_useManualAudioSwitch.on = YES;
[self addSubview:_useManualAudioSwitch];
_useManualAudioLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_useManualAudioLabel.text = @"Use manual audio config";
_useManualAudioLabel.font = controlFont;
_useManualAudioLabel.textColor = controlFontColor;
[_useManualAudioLabel sizeToFit];
[self addSubview:_useManualAudioLabel];
_startCallButton = [UIButton buttonWithType:UIButtonTypeSystem];
[_startCallButton setTitle:@"Start call"
forState:UIControlStateNormal];
@ -208,20 +155,7 @@ static CGFloat const kCallControlMargin = 8;
_callOptionsLabel.frame.size.width,
_callOptionsLabel.frame.size.height);
CGFloat audioOnlyTop =
CGRectGetMaxY(_callOptionsLabel.frame) + kCallControlMargin * 2;
CGRect audioOnlyRect = CGRectMake(kCallControlMargin * 3,
audioOnlyTop,
_audioOnlySwitch.frame.size.width,
_audioOnlySwitch.frame.size.height);
_audioOnlySwitch.frame = audioOnlyRect;
CGFloat audioOnlyLabelCenterX = CGRectGetMaxX(audioOnlyRect) +
kCallControlMargin + _audioOnlyLabel.frame.size.width / 2;
_audioOnlyLabel.center = CGPointMake(audioOnlyLabelCenterX,
CGRectGetMidY(audioOnlyRect));
CGFloat loopbackModeTop =
CGRectGetMaxY(_audioOnlySwitch.frame) + kCallControlMargin;
CGFloat loopbackModeTop = CGRectGetMaxY(_callOptionsLabel.frame) + kCallControlMargin * 2;
CGRect loopbackModeRect = CGRectMake(kCallControlMargin * 3,
loopbackModeTop,
_loopbackSwitch.frame.size.width,
@ -232,46 +166,7 @@ static CGFloat const kCallControlMargin = 8;
_loopbackLabel.center = CGPointMake(loopbackModeLabelCenterX,
CGRectGetMidY(loopbackModeRect));
CGFloat aecdumpModeTop =
CGRectGetMaxY(_loopbackSwitch.frame) + kCallControlMargin;
CGRect aecdumpModeRect = CGRectMake(kCallControlMargin * 3,
aecdumpModeTop,
_aecdumpSwitch.frame.size.width,
_aecdumpSwitch.frame.size.height);
_aecdumpSwitch.frame = aecdumpModeRect;
CGFloat aecdumpModeLabelCenterX = CGRectGetMaxX(aecdumpModeRect) +
kCallControlMargin + _aecdumpLabel.frame.size.width / 2;
_aecdumpLabel.center = CGPointMake(aecdumpModeLabelCenterX,
CGRectGetMidY(aecdumpModeRect));
CGFloat levelControlModeTop =
CGRectGetMaxY(_aecdumpSwitch.frame) + kCallControlMargin;
CGRect levelControlModeRect = CGRectMake(kCallControlMargin * 3,
levelControlModeTop,
_levelControlSwitch.frame.size.width,
_levelControlSwitch.frame.size.height);
_levelControlSwitch.frame = levelControlModeRect;
CGFloat levelControlModeLabelCenterX = CGRectGetMaxX(levelControlModeRect) +
kCallControlMargin + _levelControlLabel.frame.size.width / 2;
_levelControlLabel.center = CGPointMake(levelControlModeLabelCenterX,
CGRectGetMidY(levelControlModeRect));
CGFloat useManualAudioTop =
CGRectGetMaxY(_levelControlSwitch.frame) + kCallControlMargin;
CGRect useManualAudioRect =
CGRectMake(kCallControlMargin * 3,
useManualAudioTop,
_useManualAudioSwitch.frame.size.width,
_useManualAudioSwitch.frame.size.height);
_useManualAudioSwitch.frame = useManualAudioRect;
CGFloat useManualAudioLabelCenterX = CGRectGetMaxX(useManualAudioRect) +
kCallControlMargin + _useManualAudioLabel.frame.size.width / 2;
_useManualAudioLabel.center =
CGPointMake(useManualAudioLabelCenterX,
CGRectGetMidY(useManualAudioRect));
CGFloat audioLoopTop =
CGRectGetMaxY(useManualAudioRect) + kCallControlMargin * 3;
CGFloat audioLoopTop = CGRectGetMaxY(loopbackModeRect) + kCallControlMargin * 3;
_audioLoopButton.frame = CGRectMake(kCallControlMargin,
audioLoopTop,
_audioLoopButton.frame.size.width,
@ -304,13 +199,7 @@ static CGFloat const kCallControlMargin = 8;
}
- (void)onStartCall:(id)sender {
[_delegate mainView:self
didInputRoom:_roomText.roomText
isLoopback:_loopbackSwitch.isOn
isAudioOnly:_audioOnlySwitch.isOn
shouldMakeAecDump:_aecdumpSwitch.isOn
shouldUseLevelControl:_levelControlSwitch.isOn
useManualAudio:_useManualAudioSwitch.isOn];
[_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:_loopbackSwitch.isOn];
}
@end

View File

@ -44,13 +44,7 @@ static NSString *const loopbackLaunchProcessArgument = @"loopback";
- (void)viewDidLoad {
[super viewDidLoad];
if ([[[NSProcessInfo processInfo] arguments] containsObject:loopbackLaunchProcessArgument]) {
[self mainView:nil
didInputRoom:@""
isLoopback:YES
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO
useManualAudio:NO];
[self mainView:nil didInputRoom:@"" isLoopback:YES];
}
}
@ -91,13 +85,7 @@ static NSString *const loopbackLaunchProcessArgument = @"loopback";
#pragma mark - ARDMainViewDelegate
- (void)mainView:(ARDMainView *)mainView
didInputRoom:(NSString *)room
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl
useManualAudio:(BOOL)useManualAudio {
- (void)mainView:(ARDMainView *)mainView didInputRoom:(NSString *)room isLoopback:(BOOL)isLoopback {
if (!room.length) {
if (isLoopback) {
// If this is a loopback call, allow a generated room name.
@ -132,17 +120,16 @@ static NSString *const loopbackLaunchProcessArgument = @"loopback";
return;
}
ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
RTCAudioSession *session = [RTCAudioSession sharedInstance];
session.useManualAudio = useManualAudio;
session.useManualAudio = [settingsModel currentUseManualAudioConfigSettingFromStore];
session.isAudioEnabled = NO;
// Kick off the video call.
ARDVideoCallViewController *videoCallViewController =
[[ARDVideoCallViewController alloc] initForRoom:trimmedRoom
isLoopback:isLoopback
isAudioOnly:isAudioOnly
shouldMakeAecDump:shouldMakeAecDump
shouldUseLevelControl:shouldUseLevelControl
delegate:self];
videoCallViewController.modalTransitionStyle =
UIModalTransitionStyleCrossDissolve;

View File

@ -14,11 +14,19 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(int, ARDSettingsSections) {
ARDSettingsSectionVideoResolution = 0,
ARDSettingsSectionAudioSettings = 0,
ARDSettingsSectionVideoResolution,
ARDSettingsSectionVideoCodec,
ARDSettingsSectionBitRate,
};
typedef NS_ENUM(int, ARDAudioSettingsOptions) {
ARDAudioSettingsAudioOnly = 0,
ARDAudioSettingsCreateAecDump,
ARDAudioSettingsUseLevelController,
ARDAudioSettingsUseManualAudioConfig,
};
@interface ARDSettingsViewController () <UITextFieldDelegate> {
ARDSettingsModel *_settingsModel;
}
@ -46,22 +54,16 @@ typedef NS_ENUM(int, ARDSettingsSections) {
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self addCheckmarkInSection:ARDSettingsSectionVideoResolution
withArray:[self videoResolutionArray]
selecting:[_settingsModel currentVideoResolutionSettingFromStore]];
[self addCheckmarkInSection:ARDSettingsSectionVideoCodec
withArray:[self videoCodecArray]
selecting:[_settingsModel currentVideoCodecSettingFromStore]];
}
#pragma mark - Data source
- (NSArray<NSString *> *)videoResolutionArray {
return _settingsModel.availableVideoResolutions;
return [_settingsModel availableVideoResolutions];
}
- (NSArray<NSString *> *)videoCodecArray {
return _settingsModel.availableVideoCodecs;
return [_settingsModel availableVideoCodecs];
}
#pragma mark -
@ -74,16 +76,6 @@ typedef NS_ENUM(int, ARDSettingsSections) {
self.navigationItem.leftBarButtonItem = barItem;
}
- (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
- (void)dismissModally:(id)sender {
@ -93,11 +85,13 @@ typedef NS_ENUM(int, ARDSettingsSections) {
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
return 4;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
switch (section) {
case ARDSettingsSectionAudioSettings:
return 4;
case ARDSettingsSectionVideoResolution:
return self.videoResolutionArray.count;
case ARDSettingsSectionVideoCodec:
@ -133,6 +127,8 @@ updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
- (nullable NSString *)tableView:(UITableView *)tableView
titleForHeaderInSection:(NSInteger)section {
switch (section) {
case ARDSettingsSectionAudioSettings:
return @"Audio";
case ARDSettingsSectionVideoResolution:
return @"Video resolution";
case ARDSettingsSectionVideoCodec:
@ -147,6 +143,9 @@ updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case ARDSettingsSectionAudioSettings:
return [self audioSettingsTableViewCellForTableView:tableView atIndexPath:indexPath];
case ARDSettingsSectionVideoResolution:
return [self videoResolutionTableViewCellForTableView:tableView atIndexPath:indexPath];
@ -184,7 +183,14 @@ updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:dequeueIdentifier];
}
cell.textLabel.text = self.videoResolutionArray[indexPath.row];
NSString *resolution = self.videoResolutionArray[indexPath.row];
cell.textLabel.text = resolution;
if ([resolution isEqualToString:[_settingsModel currentVideoResolutionSettingFromStore]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
@ -208,7 +214,13 @@ updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:dequeueIdentifier];
}
cell.textLabel.text = self.videoCodecArray[indexPath.row];
NSString *codec = self.videoCodecArray[indexPath.row];
cell.textLabel.text = codec;
if ([codec isEqualToString:[_settingsModel currentVideoCodecSettingFromStore]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
@ -275,5 +287,83 @@ updateListSelectionAtIndexPath:(NSIndexPath *)indexPath
[_settingsModel storeMaxBitrateSetting:bitrateNumber];
}
#pragma mark - Table view delegate(Audio settings)
- (UITableViewCell *)audioSettingsTableViewCellForTableView:(UITableView *)tableView
atIndexPath:(NSIndexPath *)indexPath {
NSString *dequeueIdentifier = @"ARDSettingsAudioSettingsCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:dequeueIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
switchView.tag = indexPath.row;
[switchView addTarget:self
action:@selector(audioSettingSwitchChanged:)
forControlEvents:UIControlEventValueChanged];
cell.accessoryView = switchView;
}
cell.textLabel.text = [self labelForAudioSettingAtIndexPathRow:indexPath.row];
UISwitch *switchView = (UISwitch *)cell.accessoryView;
switchView.on = [self valueForAudioSettingAtIndexPathRow:indexPath.row];
return cell;
}
- (NSString *)labelForAudioSettingAtIndexPathRow:(NSInteger)setting {
switch (setting) {
case ARDAudioSettingsAudioOnly:
return @"Audio only";
case ARDAudioSettingsCreateAecDump:
return @"Create AecDump";
case ARDAudioSettingsUseLevelController:
return @"Use level controller";
case ARDAudioSettingsUseManualAudioConfig:
return @"Use manual audio config";
default:
return @"";
}
}
- (BOOL)valueForAudioSettingAtIndexPathRow:(NSInteger)setting {
switch (setting) {
case ARDAudioSettingsAudioOnly:
return [_settingsModel currentAudioOnlySettingFromStore];
case ARDAudioSettingsCreateAecDump:
return [_settingsModel currentCreateAecDumpSettingFromStore];
case ARDAudioSettingsUseLevelController:
return [_settingsModel currentUseLevelControllerSettingFromStore];
case ARDAudioSettingsUseManualAudioConfig:
return [_settingsModel currentUseManualAudioConfigSettingFromStore];
default:
return NO;
}
}
- (void)audioSettingSwitchChanged:(UISwitch *)sender {
switch (sender.tag) {
case ARDAudioSettingsAudioOnly: {
[_settingsModel storeAudioOnlySetting:sender.isOn];
break;
}
case ARDAudioSettingsCreateAecDump: {
[_settingsModel storeCreateAecDumpSetting:sender.isOn];
break;
}
case ARDAudioSettingsUseLevelController: {
[_settingsModel storeUseLevelControllerSetting:sender.isOn];
break;
}
case ARDAudioSettingsUseManualAudioConfig: {
[_settingsModel storeUseManualAudioConfigSetting:sender.isOn];
break;
}
default:
break;
}
}
@end
NS_ASSUME_NONNULL_END

View File

@ -23,9 +23,6 @@
- (instancetype)initForRoom:(NSString *)room
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl
delegate:(id<ARDVideoCallViewControllerDelegate>)delegate;
@end

View File

@ -40,21 +40,13 @@
- (instancetype)initForRoom:(NSString *)room
isLoopback:(BOOL)isLoopback
isAudioOnly:(BOOL)isAudioOnly
shouldMakeAecDump:(BOOL)shouldMakeAecDump
shouldUseLevelControl:(BOOL)shouldUseLevelControl
delegate:(id<ARDVideoCallViewControllerDelegate>)delegate {
if (self = [super init]) {
ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init];
_delegate = delegate;
_client = [[ARDAppClient alloc] initWithDelegate:self];
[_client connectToRoomWithId:room
settings:settingsModel
isLoopback:isLoopback
isAudioOnly:isAudioOnly
shouldMakeAecDump:shouldMakeAecDump
shouldUseLevelControl:shouldUseLevelControl];
[_client connectToRoomWithId:room settings:settingsModel isLoopback:isLoopback];
}
return self;
}

View File

@ -402,10 +402,7 @@ static NSUInteger const kBottomViewHeight = 200;
ARDAppClient* client = [[ARDAppClient alloc] initWithDelegate:self];
[client connectToRoomWithId:roomId
settings:[[ARDSettingsModel alloc] init] // Use default settings.
isLoopback:isLoopback
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO];
isLoopback:isLoopback];
_client = client;
}

View File

@ -116,6 +116,15 @@
return mockTURNClient;
}
- (id)mockSettingsModel {
ARDSettingsModel *model = [[ARDSettingsModel alloc] init];
id partialMock = [OCMockObject partialMockForObject:model];
[[[partialMock stub] andReturn:@[ @"640x480", @"960x540", @"1280x720" ]]
availableVideoResolutions];
return model;
}
- (ARDAppClient *)createAppClientForRoomId:(NSString *)roomId
clientId:(NSString *)clientId
isInitiator:(BOOL)isInitiator
@ -209,18 +218,8 @@
weakAnswerer = answerer;
// Kick off connection.
[caller connectToRoomWithId:roomId
settings:[[ARDSettingsModel alloc] init]
isLoopback:NO
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO];
[answerer connectToRoomWithId:roomId
settings:[[ARDSettingsModel alloc] init]
isLoopback:NO
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO];
[caller connectToRoomWithId:roomId settings:[self mockSettingsModel] isLoopback:NO];
[answerer connectToRoomWithId:roomId settings:[self mockSettingsModel] isLoopback:NO];
[self waitForExpectationsWithTimeout:20 handler:^(NSError *error) {
if (error) {
XCTFail(@"Expectation failed with error %@.", error);
@ -253,11 +252,8 @@
// Kick off connection.
[caller connectToRoomWithId:roomId
settings:[[ARDSettingsModel alloc] init]
isLoopback:NO
isAudioOnly:NO
shouldMakeAecDump:NO
shouldUseLevelControl:NO];
settings:[self mockSettingsModel]
isLoopback:NO];
[self waitForExpectationsWithTimeout:20 handler:^(NSError *error) {
if (error) {
XCTFail("Expectation timed out with error: %@.", error);

View File

@ -25,9 +25,8 @@
@implementation ARDSettingsModelTests
- (id)setupMockStoreWithVideoResolution:(NSString *)videoResolution {
- (id)setupMockStore {
id storeMock = [OCMockObject mockForClass:[ARDSettingsStore class]];
[([[storeMock stub] andReturn:videoResolution])videoResolution];
id partialMock = [OCMockObject partialMockForObject:_model];
[[[partialMock stub] andReturn:storeMock] settingsStore];
@ -41,39 +40,57 @@
_model = [[ARDSettingsModel alloc] init];
}
- (void)testDefaultMediaFromStore {
id storeMock = [self setupMockStoreWithVideoResolution:nil];
[[storeMock expect] setVideoResolution:@"640x480"];
- (void)testRetrievingSetting {
id storeMock = [self setupMockStore];
[[[storeMock expect] andReturn:@"640x480"] videoResolution];
NSString *string = [_model currentVideoResolutionSettingFromStore];
XCTAssertEqualObjects(string, @"640x480");
[storeMock verify];
}
- (void)testStoringInvalidConstraintReturnsNo {
__unused id storeMock = [self setupMockStoreWithVideoResolution:@"960x480"];
id storeMock = [self setupMockStore];
[([[storeMock stub] andReturn:@"960x480"])videoResolution];
XCTAssertFalse([_model storeVideoResolutionSetting:@"960x480"]);
}
- (void)testWidthConstraintFromStore {
[self setupMockStoreWithVideoResolution:@"1270x480"];
id storeMock = [self setupMockStore];
[([[storeMock stub] andReturn:@"1270x480"])videoResolution];
int width = [_model currentVideoResolutionWidthFromStore];
XCTAssertEqual(width, 1270);
}
- (void)testHeightConstraintFromStore {
[self setupMockStoreWithVideoResolution:@"960x540"];
id storeMock = [self setupMockStore];
[([[storeMock stub] andReturn:@"960x540"])videoResolution];
int height = [_model currentVideoResolutionHeightFromStore];
XCTAssertEqual(height, 540);
}
- (void)testConstraintComponentIsNilWhenInvalidConstraintString {
[self setupMockStoreWithVideoResolution:@"invalid"];
id storeMock = [self setupMockStore];
[([[storeMock stub] andReturn:@"invalid"])videoResolution];
int width = [_model currentVideoResolutionWidthFromStore];
XCTAssertEqual(width, 0);
}
- (void)testStoringAudioSetting {
id storeMock = [self setupMockStore];
[[storeMock expect] setAudioOnly:YES];
[_model storeAudioOnlySetting:YES];
[storeMock verify];
}
- (void)testReturningDefaultCallOption {
id storeMock = [self setupMockStore];
[[[storeMock stub] andReturnValue:@YES] useManualAudioConfig];
XCTAssertTrue([_model currentUseManualAudioConfigSettingFromStore]);
}
@end