1/* 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#import "ARDSettingsViewController.h" 12#import "ARDSettingsModel.h" 13#import "RTCVideoCodecInfo+HumanReadable.h" 14 15NS_ASSUME_NONNULL_BEGIN 16 17typedef NS_ENUM(int, ARDSettingsSections) { 18 ARDSettingsSectionAudioSettings = 0, 19 ARDSettingsSectionVideoResolution, 20 ARDSettingsSectionVideoCodec, 21 ARDSettingsSectionBitRate, 22}; 23 24typedef NS_ENUM(int, ARDAudioSettingsOptions) { 25 ARDAudioSettingsAudioOnly = 0, 26 ARDAudioSettingsCreateAecDump, 27 ARDAudioSettingsUseManualAudioConfig, 28}; 29 30@interface ARDSettingsViewController () <UITextFieldDelegate> { 31 ARDSettingsModel *_settingsModel; 32} 33 34@end 35 36@implementation ARDSettingsViewController 37 38- (instancetype)initWithStyle:(UITableViewStyle)style 39 settingsModel:(ARDSettingsModel *)settingsModel { 40 self = [super initWithStyle:style]; 41 if (self) { 42 _settingsModel = settingsModel; 43 } 44 return self; 45} 46 47#pragma mark - View lifecycle 48 49- (void)viewDidLoad { 50 [super viewDidLoad]; 51 self.title = @"Settings"; 52 [self addDoneBarButton]; 53} 54 55- (void)viewWillAppear:(BOOL)animated { 56 [super viewWillAppear:animated]; 57} 58 59#pragma mark - Data source 60 61- (NSArray<NSString *> *)videoResolutionArray { 62 return [_settingsModel availableVideoResolutions]; 63} 64 65- (NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)videoCodecArray { 66 return [_settingsModel availableVideoCodecs]; 67} 68 69#pragma mark - 70 71- (void)addDoneBarButton { 72 UIBarButtonItem *barItem = 73 [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone 74 target:self 75 action:@selector(dismissModally:)]; 76 self.navigationItem.leftBarButtonItem = barItem; 77} 78 79#pragma mark - Dismissal of view controller 80 81- (void)dismissModally:(id)sender { 82 [self dismissViewControllerAnimated:YES completion:nil]; 83} 84 85#pragma mark - Table view data source 86 87- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 88 return 4; 89} 90 91- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 92 switch (section) { 93 case ARDSettingsSectionAudioSettings: 94 return 3; 95 case ARDSettingsSectionVideoResolution: 96 return self.videoResolutionArray.count; 97 case ARDSettingsSectionVideoCodec: 98 return self.videoCodecArray.count; 99 default: 100 return 1; 101 } 102} 103 104#pragma mark - Table view delegate helpers 105 106- (void)removeAllAccessories:(UITableView *)tableView 107 inSection:(int)section 108{ 109 for (int i = 0; i < [tableView numberOfRowsInSection:section]; i++) { 110 NSIndexPath *rowPath = [NSIndexPath indexPathForRow:i inSection:section]; 111 UITableViewCell *cell = [tableView cellForRowAtIndexPath:rowPath]; 112 cell.accessoryType = UITableViewCellAccessoryNone; 113 } 114} 115 116- (void)tableView:(UITableView *)tableView 117updateListSelectionAtIndexPath:(NSIndexPath *)indexPath 118 inSection:(int)section { 119 [self removeAllAccessories:tableView inSection:section]; 120 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 121 cell.accessoryType = UITableViewCellAccessoryCheckmark; 122 [tableView deselectRowAtIndexPath:indexPath animated:YES]; 123} 124 125#pragma mark - Table view delegate 126 127- (nullable NSString *)tableView:(UITableView *)tableView 128 titleForHeaderInSection:(NSInteger)section { 129 switch (section) { 130 case ARDSettingsSectionAudioSettings: 131 return @"Audio"; 132 case ARDSettingsSectionVideoResolution: 133 return @"Video resolution"; 134 case ARDSettingsSectionVideoCodec: 135 return @"Video codec"; 136 case ARDSettingsSectionBitRate: 137 return @"Maximum bitrate"; 138 default: 139 return @""; 140 } 141} 142 143- (UITableViewCell *)tableView:(UITableView *)tableView 144 cellForRowAtIndexPath:(NSIndexPath *)indexPath { 145 switch (indexPath.section) { 146 case ARDSettingsSectionAudioSettings: 147 return [self audioSettingsTableViewCellForTableView:tableView atIndexPath:indexPath]; 148 149 case ARDSettingsSectionVideoResolution: 150 return [self videoResolutionTableViewCellForTableView:tableView atIndexPath:indexPath]; 151 152 case ARDSettingsSectionVideoCodec: 153 return [self videoCodecTableViewCellForTableView:tableView atIndexPath:indexPath]; 154 155 case ARDSettingsSectionBitRate: 156 return [self bitrateTableViewCellForTableView:tableView atIndexPath:indexPath]; 157 158 default: 159 return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 160 reuseIdentifier:@"identifier"]; 161 } 162} 163 164- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 165 switch (indexPath.section) { 166 case ARDSettingsSectionVideoResolution: 167 [self tableView:tableView disSelectVideoResolutionAtIndex:indexPath]; 168 break; 169 170 case ARDSettingsSectionVideoCodec: 171 [self tableView:tableView didSelectVideoCodecCellAtIndexPath:indexPath]; 172 break; 173 } 174} 175 176#pragma mark - Table view delegate(Video Resolution) 177 178- (UITableViewCell *)videoResolutionTableViewCellForTableView:(UITableView *)tableView 179 atIndexPath:(NSIndexPath *)indexPath { 180 NSString *dequeueIdentifier = @"ARDSettingsVideoResolutionViewCellIdentifier"; 181 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; 182 if (!cell) { 183 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 184 reuseIdentifier:dequeueIdentifier]; 185 } 186 NSString *resolution = self.videoResolutionArray[indexPath.row]; 187 cell.textLabel.text = resolution; 188 if ([resolution isEqualToString:[_settingsModel currentVideoResolutionSettingFromStore]]) { 189 cell.accessoryType = UITableViewCellAccessoryCheckmark; 190 } else { 191 cell.accessoryType = UITableViewCellAccessoryNone; 192 } 193 194 return cell; 195} 196 197- (void)tableView:(UITableView *)tableView 198 disSelectVideoResolutionAtIndex:(NSIndexPath *)indexPath { 199 [self tableView:tableView 200 updateListSelectionAtIndexPath:indexPath 201 inSection:ARDSettingsSectionVideoResolution]; 202 203 NSString *videoResolution = self.videoResolutionArray[indexPath.row]; 204 [_settingsModel storeVideoResolutionSetting:videoResolution]; 205} 206 207#pragma mark - Table view delegate(Video Codec) 208 209- (UITableViewCell *)videoCodecTableViewCellForTableView:(UITableView *)tableView 210 atIndexPath:(NSIndexPath *)indexPath { 211 NSString *dequeueIdentifier = @"ARDSettingsVideoCodecCellIdentifier"; 212 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; 213 if (!cell) { 214 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 215 reuseIdentifier:dequeueIdentifier]; 216 } 217 RTC_OBJC_TYPE(RTCVideoCodecInfo) *codec = self.videoCodecArray[indexPath.row]; 218 cell.textLabel.text = [codec humanReadableDescription]; 219 if ([codec isEqualToCodecInfo:[_settingsModel currentVideoCodecSettingFromStore]]) { 220 cell.accessoryType = UITableViewCellAccessoryCheckmark; 221 } else { 222 cell.accessoryType = UITableViewCellAccessoryNone; 223 } 224 225 return cell; 226} 227 228- (void)tableView:(UITableView *)tableView 229 didSelectVideoCodecCellAtIndexPath:(NSIndexPath *)indexPath { 230 [self tableView:tableView 231 updateListSelectionAtIndexPath:indexPath 232 inSection:ARDSettingsSectionVideoCodec]; 233 234 RTC_OBJC_TYPE(RTCVideoCodecInfo) *videoCodec = self.videoCodecArray[indexPath.row]; 235 [_settingsModel storeVideoCodecSetting:videoCodec]; 236} 237 238#pragma mark - Table view delegate(Bitrate) 239 240- (UITableViewCell *)bitrateTableViewCellForTableView:(UITableView *)tableView 241 atIndexPath:(NSIndexPath *)indexPath { 242 NSString *dequeueIdentifier = @"ARDSettingsBitrateCellIdentifier"; 243 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; 244 if (!cell) { 245 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 246 reuseIdentifier:dequeueIdentifier]; 247 248 UITextField *textField = [[UITextField alloc] 249 initWithFrame:CGRectMake(10, 0, cell.bounds.size.width - 20, cell.bounds.size.height)]; 250 NSString *currentMaxBitrate = [_settingsModel currentMaxBitrateSettingFromStore].stringValue; 251 textField.text = currentMaxBitrate; 252 textField.placeholder = @"Enter max bit rate (kbps)"; 253 textField.keyboardType = UIKeyboardTypeNumberPad; 254 textField.delegate = self; 255 256 // Numerical keyboards have no return button, we need to add one manually. 257 UIToolbar *numberToolbar = 258 [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; 259 numberToolbar.items = @[ 260 [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace 261 target:nil 262 action:nil], 263 [[UIBarButtonItem alloc] initWithTitle:@"Apply" 264 style:UIBarButtonItemStyleDone 265 target:self 266 action:@selector(numberTextFieldDidEndEditing:)] 267 ]; 268 [numberToolbar sizeToFit]; 269 270 textField.inputAccessoryView = numberToolbar; 271 [cell addSubview:textField]; 272 } 273 return cell; 274} 275 276- (void)numberTextFieldDidEndEditing:(id)sender { 277 [self.view endEditing:YES]; 278} 279 280- (void)textFieldDidEndEditing:(UITextField *)textField { 281 NSNumber *bitrateNumber = nil; 282 283 if (textField.text.length != 0) { 284 bitrateNumber = [NSNumber numberWithInteger:textField.text.intValue]; 285 } 286 287 [_settingsModel storeMaxBitrateSetting:bitrateNumber]; 288} 289 290#pragma mark - Table view delegate(Audio settings) 291 292- (UITableViewCell *)audioSettingsTableViewCellForTableView:(UITableView *)tableView 293 atIndexPath:(NSIndexPath *)indexPath { 294 NSString *dequeueIdentifier = @"ARDSettingsAudioSettingsCellIdentifier"; 295 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; 296 if (!cell) { 297 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 298 reuseIdentifier:dequeueIdentifier]; 299 cell.selectionStyle = UITableViewCellSelectionStyleNone; 300 UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero]; 301 switchView.tag = indexPath.row; 302 [switchView addTarget:self 303 action:@selector(audioSettingSwitchChanged:) 304 forControlEvents:UIControlEventValueChanged]; 305 cell.accessoryView = switchView; 306 } 307 308 cell.textLabel.text = [self labelForAudioSettingAtIndexPathRow:indexPath.row]; 309 UISwitch *switchView = (UISwitch *)cell.accessoryView; 310 switchView.on = [self valueForAudioSettingAtIndexPathRow:indexPath.row]; 311 312 return cell; 313} 314 315- (NSString *)labelForAudioSettingAtIndexPathRow:(NSInteger)setting { 316 switch (setting) { 317 case ARDAudioSettingsAudioOnly: 318 return @"Audio only"; 319 case ARDAudioSettingsCreateAecDump: 320 return @"Create AecDump"; 321 case ARDAudioSettingsUseManualAudioConfig: 322 return @"Use manual audio config"; 323 default: 324 return @""; 325 } 326} 327 328- (BOOL)valueForAudioSettingAtIndexPathRow:(NSInteger)setting { 329 switch (setting) { 330 case ARDAudioSettingsAudioOnly: 331 return [_settingsModel currentAudioOnlySettingFromStore]; 332 case ARDAudioSettingsCreateAecDump: 333 return [_settingsModel currentCreateAecDumpSettingFromStore]; 334 case ARDAudioSettingsUseManualAudioConfig: 335 return [_settingsModel currentUseManualAudioConfigSettingFromStore]; 336 default: 337 return NO; 338 } 339} 340 341- (void)audioSettingSwitchChanged:(UISwitch *)sender { 342 switch (sender.tag) { 343 case ARDAudioSettingsAudioOnly: { 344 [_settingsModel storeAudioOnlySetting:sender.isOn]; 345 break; 346 } 347 case ARDAudioSettingsCreateAecDump: { 348 [_settingsModel storeCreateAecDumpSetting:sender.isOn]; 349 break; 350 } 351 case ARDAudioSettingsUseManualAudioConfig: { 352 [_settingsModel storeUseManualAudioConfigSetting:sender.isOn]; 353 break; 354 } 355 default: 356 break; 357 } 358} 359 360@end 361NS_ASSUME_NONNULL_END 362