| /* | |
| * Copyright 2016 The WebRTC Project Authors. All rights reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #import "ARDSettingsViewController.h" | |
| #import "ARDSettingsModel.h" | |
| #import "RTCVideoCodecInfo+HumanReadable.h" | |
| NS_ASSUME_NONNULL_BEGIN | |
| typedef NS_ENUM(int, ARDSettingsSections) { | |
| ARDSettingsSectionAudioSettings = 0, | |
| ARDSettingsSectionVideoResolution, | |
| ARDSettingsSectionVideoCodec, | |
| ARDSettingsSectionBitRate, | |
| }; | |
| typedef NS_ENUM(int, ARDAudioSettingsOptions) { | |
| ARDAudioSettingsAudioOnly = 0, | |
| ARDAudioSettingsCreateAecDump, | |
| ARDAudioSettingsUseManualAudioConfig, | |
| }; | |
| @interface ARDSettingsViewController () <UITextFieldDelegate> { | |
| ARDSettingsModel *_settingsModel; | |
| } | |
| @end | |
| @implementation ARDSettingsViewController | |
| - (instancetype)initWithStyle:(UITableViewStyle)style | |
| settingsModel:(ARDSettingsModel *)settingsModel { | |
| self = [super initWithStyle:style]; | |
| if (self) { | |
| _settingsModel = settingsModel; | |
| } | |
| return self; | |
| } | |
| #pragma mark - View lifecycle | |
| - (void)viewDidLoad { | |
| [super viewDidLoad]; | |
| self.title = @"Settings"; | |
| [self addDoneBarButton]; | |
| } | |
| - (void)viewWillAppear:(BOOL)animated { | |
| [super viewWillAppear:animated]; | |
| } | |
| #pragma mark - Data source | |
| - (NSArray<NSString *> *)videoResolutionArray { | |
| return [_settingsModel availableVideoResolutions]; | |
| } | |
| - (NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)videoCodecArray { | |
| return [_settingsModel availableVideoCodecs]; | |
| } | |
| #pragma mark - | |
| - (void)addDoneBarButton { | |
| UIBarButtonItem *barItem = [[UIBarButtonItem alloc] | |
| initWithBarButtonSystemItem:UIBarButtonSystemItemDone | |
| target:self | |
| action:@selector(dismissModally:)]; | |
| self.navigationItem.leftBarButtonItem = barItem; | |
| } | |
| #pragma mark - Dismissal of view controller | |
| - (void)dismissModally:(id)sender { | |
| [self dismissViewControllerAnimated:YES completion:nil]; | |
| } | |
| #pragma mark - Table view data source | |
| - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { | |
| return 4; | |
| } | |
| - (NSInteger)tableView:(UITableView *)tableView | |
| numberOfRowsInSection:(NSInteger)section { | |
| switch (section) { | |
| case ARDSettingsSectionAudioSettings: | |
| return 3; | |
| case ARDSettingsSectionVideoResolution: | |
| return self.videoResolutionArray.count; | |
| case ARDSettingsSectionVideoCodec: | |
| return self.videoCodecArray.count; | |
| default: | |
| return 1; | |
| } | |
| } | |
| #pragma mark - Table view delegate helpers | |
| - (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; | |
| } | |
| } | |
| - (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 { | |
| switch (section) { | |
| case ARDSettingsSectionAudioSettings: | |
| return @"Audio"; | |
| case ARDSettingsSectionVideoResolution: | |
| return @"Video resolution"; | |
| case ARDSettingsSectionVideoCodec: | |
| return @"Video codec"; | |
| case ARDSettingsSectionBitRate: | |
| return @"Maximum bitrate"; | |
| default: | |
| return @""; | |
| } | |
| } | |
| - (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]; | |
| case ARDSettingsSectionVideoCodec: | |
| return [self videoCodecTableViewCellForTableView:tableView | |
| atIndexPath:indexPath]; | |
| case ARDSettingsSectionBitRate: | |
| return [self bitrateTableViewCellForTableView:tableView | |
| atIndexPath:indexPath]; | |
| default: | |
| return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault | |
| reuseIdentifier:@"identifier"]; | |
| } | |
| } | |
| - (void)tableView:(UITableView *)tableView | |
| didSelectRowAtIndexPath:(NSIndexPath *)indexPath { | |
| switch (indexPath.section) { | |
| case ARDSettingsSectionVideoResolution: | |
| [self tableView:tableView disSelectVideoResolutionAtIndex:indexPath]; | |
| break; | |
| case ARDSettingsSectionVideoCodec: | |
| [self tableView:tableView didSelectVideoCodecCellAtIndexPath:indexPath]; | |
| break; | |
| } | |
| } | |
| #pragma mark - Table view delegate(Video Resolution) | |
| - (UITableViewCell *) | |
| videoResolutionTableViewCellForTableView:(UITableView *)tableView | |
| atIndexPath:(NSIndexPath *)indexPath { | |
| NSString *dequeueIdentifier = @"ARDSettingsVideoResolutionViewCellIdentifier"; | |
| UITableViewCell *cell = | |
| [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; | |
| if (!cell) { | |
| cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault | |
| reuseIdentifier:dequeueIdentifier]; | |
| } | |
| NSString *resolution = self.videoResolutionArray[indexPath.row]; | |
| cell.textLabel.text = resolution; | |
| if ([resolution | |
| isEqualToString:[_settingsModel | |
| currentVideoResolutionSettingFromStore]]) { | |
| cell.accessoryType = UITableViewCellAccessoryCheckmark; | |
| } else { | |
| cell.accessoryType = UITableViewCellAccessoryNone; | |
| } | |
| return cell; | |
| } | |
| - (void)tableView:(UITableView *)tableView | |
| disSelectVideoResolutionAtIndex:(NSIndexPath *)indexPath { | |
| [self tableView:tableView | |
| updateListSelectionAtIndexPath:indexPath | |
| inSection:ARDSettingsSectionVideoResolution]; | |
| NSString *videoResolution = self.videoResolutionArray[indexPath.row]; | |
| [_settingsModel storeVideoResolutionSetting:videoResolution]; | |
| } | |
| #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]; | |
| } | |
| RTC_OBJC_TYPE(RTCVideoCodecInfo) *codec = self.videoCodecArray[indexPath.row]; | |
| cell.textLabel.text = [codec humanReadableDescription]; | |
| if ([codec isEqualToCodecInfo:[_settingsModel | |
| currentVideoCodecSettingFromStore]]) { | |
| cell.accessoryType = UITableViewCellAccessoryCheckmark; | |
| } else { | |
| cell.accessoryType = UITableViewCellAccessoryNone; | |
| } | |
| return cell; | |
| } | |
| - (void)tableView:(UITableView *)tableView | |
| didSelectVideoCodecCellAtIndexPath:(NSIndexPath *)indexPath { | |
| [self tableView:tableView | |
| updateListSelectionAtIndexPath:indexPath | |
| inSection:ARDSettingsSectionVideoCodec]; | |
| RTC_OBJC_TYPE(RTCVideoCodecInfo) *videoCodec = | |
| self.videoCodecArray[indexPath.row]; | |
| [_settingsModel storeVideoCodecSetting:videoCodec]; | |
| } | |
| #pragma mark - Table view delegate(Bitrate) | |
| - (UITableViewCell *)bitrateTableViewCellForTableView:(UITableView *)tableView | |
| atIndexPath:(NSIndexPath *)indexPath { | |
| NSString *dequeueIdentifier = @"ARDSettingsBitrateCellIdentifier"; | |
| UITableViewCell *cell = | |
| [tableView dequeueReusableCellWithIdentifier:dequeueIdentifier]; | |
| if (!cell) { | |
| cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault | |
| reuseIdentifier:dequeueIdentifier]; | |
| UITextField *textField = [[UITextField alloc] | |
| initWithFrame:CGRectMake(10, | |
| 0, | |
| cell.bounds.size.width - 20, | |
| cell.bounds.size.height)]; | |
| NSString *currentMaxBitrate = | |
| [_settingsModel currentMaxBitrateSettingFromStore].stringValue; | |
| textField.text = currentMaxBitrate; | |
| textField.placeholder = @"Enter max bit rate (kbps)"; | |
| textField.keyboardType = UIKeyboardTypeNumberPad; | |
| textField.delegate = self; | |
| // Numerical keyboards have no return button, we need to add one manually. | |
| UIToolbar *numberToolbar = [[UIToolbar alloc] | |
| initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; | |
| numberToolbar.items = @[ | |
| [[UIBarButtonItem alloc] | |
| initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace | |
| target:nil | |
| action:nil], | |
| [[UIBarButtonItem alloc] | |
| initWithTitle:@"Apply" | |
| style:UIBarButtonItemStyleDone | |
| target:self | |
| action:@selector(numberTextFieldDidEndEditing:)] | |
| ]; | |
| [numberToolbar sizeToFit]; | |
| textField.inputAccessoryView = numberToolbar; | |
| [cell addSubview:textField]; | |
| } | |
| return cell; | |
| } | |
| - (void)numberTextFieldDidEndEditing:(id)sender { | |
| [self.view endEditing:YES]; | |
| } | |
| - (void)textFieldDidEndEditing:(UITextField *)textField { | |
| NSNumber *bitrateNumber = nil; | |
| if (textField.text.length != 0) { | |
| bitrateNumber = [NSNumber numberWithInteger:textField.text.intValue]; | |
| } | |
| [_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 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 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 ARDAudioSettingsUseManualAudioConfig: { | |
| [_settingsModel storeUseManualAudioConfigSetting:sender.isOn]; | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| @end | |
| NS_ASSUME_NONNULL_END |