diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h b/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h index a21ac72aee..3cf40400f5 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h +++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h @@ -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; diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h index b613ec976f..8c27b345c6 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h +++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h @@ -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; diff --git a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m index 7e06612e6a..7e9fbdac75 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m +++ b/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m @@ -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 diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h index 0f07389b15..8b2679fa82 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h +++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h @@ -11,6 +11,7 @@ #import 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 diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m index 78d404a02d..0d3ca7ccb6 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m +++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m @@ -56,13 +56,8 @@ static NSArray *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 *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 *videoCodecsStaticValues() { } - (nullable NSNumber *)currentMaxBitrateSettingFromStore { + [self registerStoreDefaults]; return [[self settingsStore] maxBitrate]; } @@ -102,11 +94,44 @@ static NSArray *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 *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 *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 diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h index 3dd0f6431b..3f5f79106f 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h +++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h @@ -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 diff --git a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m index e25b28860c..8ccc438800 100644 --- a/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m +++ b/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m @@ -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 *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 diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.h b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.h index 1f2497a1e2..c6691c2d84 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.h +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.h @@ -14,14 +14,7 @@ @protocol 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; - (void)mainViewDidToggleAudioLoop:(ARDMainView *)mainView; @end diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m index 0308ea0cfd..fcce3c3015 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m @@ -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 diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainViewController.m index 0e93aae9ad..c57dace7a7 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDMainViewController.m +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDMainViewController.m @@ -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; diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m index 09a3d6d744..fce5df7117 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m @@ -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 () { 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 *)videoResolutionArray { - return _settingsModel.availableVideoResolutions; + return [_settingsModel availableVideoResolutions]; } - (NSArray *)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*) 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 diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.h b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.h index 3ca2dc2e9a..bdb8747524 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.h +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.h @@ -23,9 +23,6 @@ - (instancetype)initForRoom:(NSString *)room isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly - shouldMakeAecDump:(BOOL)shouldMakeAecDump - shouldUseLevelControl:(BOOL)shouldUseLevelControl delegate:(id)delegate; @end diff --git a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m index fd33e01e71..03ce626266 100644 --- a/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m +++ b/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m @@ -40,21 +40,13 @@ - (instancetype)initForRoom:(NSString *)room isLoopback:(BOOL)isLoopback - isAudioOnly:(BOOL)isAudioOnly - shouldMakeAecDump:(BOOL)shouldMakeAecDump - shouldUseLevelControl:(BOOL)shouldUseLevelControl delegate:(id)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; } diff --git a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m index ab65b7e6d9..cb82e88888 100644 --- a/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m +++ b/webrtc/examples/objc/AppRTCMobile/mac/APPRTCViewController.m @@ -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; } diff --git a/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClient_xctest.mm b/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClient_xctest.mm index fc7b76822c..b1ce5f0c59 100644 --- a/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClient_xctest.mm +++ b/webrtc/examples/objc/AppRTCMobile/tests/ARDAppClient_xctest.mm @@ -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); diff --git a/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm b/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm index b139b97e73..b44f9358ac 100644 --- a/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm +++ b/webrtc/examples/objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm @@ -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