1*d9f75844SAndroid Build Coastguard Worker/* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2016 The WebRTC Project Authors. All rights reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker#import "ARDSettingsModel+Private.h" 12*d9f75844SAndroid Build Coastguard Worker#import "ARDSettingsStore.h" 13*d9f75844SAndroid Build Coastguard Worker 14*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/api/peerconnection/RTCMediaConstraints.h" 15*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/capturer/RTCCameraVideoCapturer.h" 16*d9f75844SAndroid Build Coastguard Worker#import "sdk/objc/components/video_codec/RTCDefaultVideoEncoderFactory.h" 17*d9f75844SAndroid Build Coastguard Worker 18*d9f75844SAndroid Build Coastguard WorkerNS_ASSUME_NONNULL_BEGIN 19*d9f75844SAndroid Build Coastguard Worker 20*d9f75844SAndroid Build Coastguard Worker@interface ARDSettingsModel () { 21*d9f75844SAndroid Build Coastguard Worker ARDSettingsStore *_settingsStore; 22*d9f75844SAndroid Build Coastguard Worker} 23*d9f75844SAndroid Build Coastguard Worker@end 24*d9f75844SAndroid Build Coastguard Worker 25*d9f75844SAndroid Build Coastguard Worker@implementation ARDSettingsModel 26*d9f75844SAndroid Build Coastguard Worker 27*d9f75844SAndroid Build Coastguard Worker- (NSArray<NSString *> *)availableVideoResolutions { 28*d9f75844SAndroid Build Coastguard Worker NSMutableSet<NSArray<NSNumber *> *> *resolutions = 29*d9f75844SAndroid Build Coastguard Worker [[NSMutableSet<NSArray<NSNumber *> *> alloc] init]; 30*d9f75844SAndroid Build Coastguard Worker for (AVCaptureDevice *device in [RTC_OBJC_TYPE(RTCCameraVideoCapturer) captureDevices]) { 31*d9f75844SAndroid Build Coastguard Worker for (AVCaptureDeviceFormat *format in 32*d9f75844SAndroid Build Coastguard Worker [RTC_OBJC_TYPE(RTCCameraVideoCapturer) supportedFormatsForDevice:device]) { 33*d9f75844SAndroid Build Coastguard Worker CMVideoDimensions resolution = 34*d9f75844SAndroid Build Coastguard Worker CMVideoFormatDescriptionGetDimensions(format.formatDescription); 35*d9f75844SAndroid Build Coastguard Worker NSArray<NSNumber *> *resolutionObject = @[ @(resolution.width), @(resolution.height) ]; 36*d9f75844SAndroid Build Coastguard Worker [resolutions addObject:resolutionObject]; 37*d9f75844SAndroid Build Coastguard Worker } 38*d9f75844SAndroid Build Coastguard Worker } 39*d9f75844SAndroid Build Coastguard Worker 40*d9f75844SAndroid Build Coastguard Worker NSArray<NSArray<NSNumber *> *> *sortedResolutions = 41*d9f75844SAndroid Build Coastguard Worker [[resolutions allObjects] sortedArrayUsingComparator:^NSComparisonResult( 42*d9f75844SAndroid Build Coastguard Worker NSArray<NSNumber *> *obj1, NSArray<NSNumber *> *obj2) { 43*d9f75844SAndroid Build Coastguard Worker NSComparisonResult cmp = [obj1.firstObject compare:obj2.firstObject]; 44*d9f75844SAndroid Build Coastguard Worker if (cmp != NSOrderedSame) { 45*d9f75844SAndroid Build Coastguard Worker return cmp; 46*d9f75844SAndroid Build Coastguard Worker } 47*d9f75844SAndroid Build Coastguard Worker return [obj1.lastObject compare:obj2.lastObject]; 48*d9f75844SAndroid Build Coastguard Worker }]; 49*d9f75844SAndroid Build Coastguard Worker 50*d9f75844SAndroid Build Coastguard Worker NSMutableArray<NSString *> *resolutionStrings = [[NSMutableArray<NSString *> alloc] init]; 51*d9f75844SAndroid Build Coastguard Worker for (NSArray<NSNumber *> *resolution in sortedResolutions) { 52*d9f75844SAndroid Build Coastguard Worker NSString *resolutionString = 53*d9f75844SAndroid Build Coastguard Worker [NSString stringWithFormat:@"%@x%@", resolution.firstObject, resolution.lastObject]; 54*d9f75844SAndroid Build Coastguard Worker [resolutionStrings addObject:resolutionString]; 55*d9f75844SAndroid Build Coastguard Worker } 56*d9f75844SAndroid Build Coastguard Worker 57*d9f75844SAndroid Build Coastguard Worker return [resolutionStrings copy]; 58*d9f75844SAndroid Build Coastguard Worker} 59*d9f75844SAndroid Build Coastguard Worker 60*d9f75844SAndroid Build Coastguard Worker- (NSString *)currentVideoResolutionSettingFromStore { 61*d9f75844SAndroid Build Coastguard Worker [self registerStoreDefaults]; 62*d9f75844SAndroid Build Coastguard Worker return [[self settingsStore] videoResolution]; 63*d9f75844SAndroid Build Coastguard Worker} 64*d9f75844SAndroid Build Coastguard Worker 65*d9f75844SAndroid Build Coastguard Worker- (BOOL)storeVideoResolutionSetting:(NSString *)resolution { 66*d9f75844SAndroid Build Coastguard Worker if (![[self availableVideoResolutions] containsObject:resolution]) { 67*d9f75844SAndroid Build Coastguard Worker return NO; 68*d9f75844SAndroid Build Coastguard Worker } 69*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setVideoResolution:resolution]; 70*d9f75844SAndroid Build Coastguard Worker return YES; 71*d9f75844SAndroid Build Coastguard Worker} 72*d9f75844SAndroid Build Coastguard Worker 73*d9f75844SAndroid Build Coastguard Worker- (NSArray<RTC_OBJC_TYPE(RTCVideoCodecInfo) *> *)availableVideoCodecs { 74*d9f75844SAndroid Build Coastguard Worker return [RTC_OBJC_TYPE(RTCDefaultVideoEncoderFactory) supportedCodecs]; 75*d9f75844SAndroid Build Coastguard Worker} 76*d9f75844SAndroid Build Coastguard Worker 77*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)currentVideoCodecSettingFromStore { 78*d9f75844SAndroid Build Coastguard Worker [self registerStoreDefaults]; 79*d9f75844SAndroid Build Coastguard Worker NSData *codecData = [[self settingsStore] videoCodec]; 80*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13 81*d9f75844SAndroid Build Coastguard Worker Class expectedClass = [RTC_OBJC_TYPE(RTCVideoCodecInfo) class]; 82*d9f75844SAndroid Build Coastguard Worker NSError *error; 83*d9f75844SAndroid Build Coastguard Worker RTC_OBJC_TYPE(RTCVideoCodecInfo) *videoCodecSetting = 84*d9f75844SAndroid Build Coastguard Worker [NSKeyedUnarchiver unarchivedObjectOfClass:expectedClass fromData:codecData error:&error]; 85*d9f75844SAndroid Build Coastguard Worker if (!error) { 86*d9f75844SAndroid Build Coastguard Worker return videoCodecSetting; 87*d9f75844SAndroid Build Coastguard Worker } 88*d9f75844SAndroid Build Coastguard Worker return nil; 89*d9f75844SAndroid Build Coastguard Worker#else 90*d9f75844SAndroid Build Coastguard Worker return [NSKeyedUnarchiver unarchiveObjectWithData:codecData]; 91*d9f75844SAndroid Build Coastguard Worker#endif 92*d9f75844SAndroid Build Coastguard Worker} 93*d9f75844SAndroid Build Coastguard Worker 94*d9f75844SAndroid Build Coastguard Worker- (BOOL)storeVideoCodecSetting:(RTC_OBJC_TYPE(RTCVideoCodecInfo) *)videoCodec { 95*d9f75844SAndroid Build Coastguard Worker if (![[self availableVideoCodecs] containsObject:videoCodec]) { 96*d9f75844SAndroid Build Coastguard Worker return NO; 97*d9f75844SAndroid Build Coastguard Worker } 98*d9f75844SAndroid Build Coastguard Worker 99*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13 100*d9f75844SAndroid Build Coastguard Worker NSError *error; 101*d9f75844SAndroid Build Coastguard Worker NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:videoCodec 102*d9f75844SAndroid Build Coastguard Worker requiringSecureCoding:NO 103*d9f75844SAndroid Build Coastguard Worker error:&error]; 104*d9f75844SAndroid Build Coastguard Worker if (error) { 105*d9f75844SAndroid Build Coastguard Worker return NO; 106*d9f75844SAndroid Build Coastguard Worker } 107*d9f75844SAndroid Build Coastguard Worker#else 108*d9f75844SAndroid Build Coastguard Worker NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:videoCodec]; 109*d9f75844SAndroid Build Coastguard Worker#endif 110*d9f75844SAndroid Build Coastguard Worker 111*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setVideoCodec:codecData]; 112*d9f75844SAndroid Build Coastguard Worker return YES; 113*d9f75844SAndroid Build Coastguard Worker} 114*d9f75844SAndroid Build Coastguard Worker 115*d9f75844SAndroid Build Coastguard Worker- (nullable NSNumber *)currentMaxBitrateSettingFromStore { 116*d9f75844SAndroid Build Coastguard Worker [self registerStoreDefaults]; 117*d9f75844SAndroid Build Coastguard Worker return [[self settingsStore] maxBitrate]; 118*d9f75844SAndroid Build Coastguard Worker} 119*d9f75844SAndroid Build Coastguard Worker 120*d9f75844SAndroid Build Coastguard Worker- (void)storeMaxBitrateSetting:(nullable NSNumber *)bitrate { 121*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setMaxBitrate:bitrate]; 122*d9f75844SAndroid Build Coastguard Worker} 123*d9f75844SAndroid Build Coastguard Worker 124*d9f75844SAndroid Build Coastguard Worker- (BOOL)currentAudioOnlySettingFromStore { 125*d9f75844SAndroid Build Coastguard Worker return [[self settingsStore] audioOnly]; 126*d9f75844SAndroid Build Coastguard Worker} 127*d9f75844SAndroid Build Coastguard Worker 128*d9f75844SAndroid Build Coastguard Worker- (void)storeAudioOnlySetting:(BOOL)audioOnly { 129*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setAudioOnly:audioOnly]; 130*d9f75844SAndroid Build Coastguard Worker} 131*d9f75844SAndroid Build Coastguard Worker 132*d9f75844SAndroid Build Coastguard Worker- (BOOL)currentCreateAecDumpSettingFromStore { 133*d9f75844SAndroid Build Coastguard Worker return [[self settingsStore] createAecDump]; 134*d9f75844SAndroid Build Coastguard Worker} 135*d9f75844SAndroid Build Coastguard Worker 136*d9f75844SAndroid Build Coastguard Worker- (void)storeCreateAecDumpSetting:(BOOL)createAecDump { 137*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setCreateAecDump:createAecDump]; 138*d9f75844SAndroid Build Coastguard Worker} 139*d9f75844SAndroid Build Coastguard Worker 140*d9f75844SAndroid Build Coastguard Worker- (BOOL)currentUseManualAudioConfigSettingFromStore { 141*d9f75844SAndroid Build Coastguard Worker return [[self settingsStore] useManualAudioConfig]; 142*d9f75844SAndroid Build Coastguard Worker} 143*d9f75844SAndroid Build Coastguard Worker 144*d9f75844SAndroid Build Coastguard Worker- (void)storeUseManualAudioConfigSetting:(BOOL)useManualAudioConfig { 145*d9f75844SAndroid Build Coastguard Worker [[self settingsStore] setUseManualAudioConfig:useManualAudioConfig]; 146*d9f75844SAndroid Build Coastguard Worker} 147*d9f75844SAndroid Build Coastguard Worker 148*d9f75844SAndroid Build Coastguard Worker#pragma mark - Testable 149*d9f75844SAndroid Build Coastguard Worker 150*d9f75844SAndroid Build Coastguard Worker- (ARDSettingsStore *)settingsStore { 151*d9f75844SAndroid Build Coastguard Worker if (!_settingsStore) { 152*d9f75844SAndroid Build Coastguard Worker _settingsStore = [[ARDSettingsStore alloc] init]; 153*d9f75844SAndroid Build Coastguard Worker [self registerStoreDefaults]; 154*d9f75844SAndroid Build Coastguard Worker } 155*d9f75844SAndroid Build Coastguard Worker return _settingsStore; 156*d9f75844SAndroid Build Coastguard Worker} 157*d9f75844SAndroid Build Coastguard Worker 158*d9f75844SAndroid Build Coastguard Worker- (int)currentVideoResolutionWidthFromStore { 159*d9f75844SAndroid Build Coastguard Worker NSString *resolution = [self currentVideoResolutionSettingFromStore]; 160*d9f75844SAndroid Build Coastguard Worker 161*d9f75844SAndroid Build Coastguard Worker return [self videoResolutionComponentAtIndex:0 inString:resolution]; 162*d9f75844SAndroid Build Coastguard Worker} 163*d9f75844SAndroid Build Coastguard Worker 164*d9f75844SAndroid Build Coastguard Worker- (int)currentVideoResolutionHeightFromStore { 165*d9f75844SAndroid Build Coastguard Worker NSString *resolution = [self currentVideoResolutionSettingFromStore]; 166*d9f75844SAndroid Build Coastguard Worker return [self videoResolutionComponentAtIndex:1 inString:resolution]; 167*d9f75844SAndroid Build Coastguard Worker} 168*d9f75844SAndroid Build Coastguard Worker 169*d9f75844SAndroid Build Coastguard Worker#pragma mark - 170*d9f75844SAndroid Build Coastguard Worker 171*d9f75844SAndroid Build Coastguard Worker- (NSString *)defaultVideoResolutionSetting { 172*d9f75844SAndroid Build Coastguard Worker return [self availableVideoResolutions].firstObject; 173*d9f75844SAndroid Build Coastguard Worker} 174*d9f75844SAndroid Build Coastguard Worker 175*d9f75844SAndroid Build Coastguard Worker- (RTC_OBJC_TYPE(RTCVideoCodecInfo) *)defaultVideoCodecSetting { 176*d9f75844SAndroid Build Coastguard Worker return [self availableVideoCodecs].firstObject; 177*d9f75844SAndroid Build Coastguard Worker} 178*d9f75844SAndroid Build Coastguard Worker 179*d9f75844SAndroid Build Coastguard Worker- (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolution { 180*d9f75844SAndroid Build Coastguard Worker if (index != 0 && index != 1) { 181*d9f75844SAndroid Build Coastguard Worker return 0; 182*d9f75844SAndroid Build Coastguard Worker } 183*d9f75844SAndroid Build Coastguard Worker NSArray<NSString *> *components = [resolution componentsSeparatedByString:@"x"]; 184*d9f75844SAndroid Build Coastguard Worker if (components.count != 2) { 185*d9f75844SAndroid Build Coastguard Worker return 0; 186*d9f75844SAndroid Build Coastguard Worker } 187*d9f75844SAndroid Build Coastguard Worker return components[index].intValue; 188*d9f75844SAndroid Build Coastguard Worker} 189*d9f75844SAndroid Build Coastguard Worker 190*d9f75844SAndroid Build Coastguard Worker- (void)registerStoreDefaults { 191*d9f75844SAndroid Build Coastguard Worker#if defined(WEBRTC_IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13 192*d9f75844SAndroid Build Coastguard Worker NSError *error; 193*d9f75844SAndroid Build Coastguard Worker NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:[self defaultVideoCodecSetting] 194*d9f75844SAndroid Build Coastguard Worker requiringSecureCoding:NO 195*d9f75844SAndroid Build Coastguard Worker error:&error]; 196*d9f75844SAndroid Build Coastguard Worker if (error) { 197*d9f75844SAndroid Build Coastguard Worker return; 198*d9f75844SAndroid Build Coastguard Worker } 199*d9f75844SAndroid Build Coastguard Worker#else 200*d9f75844SAndroid Build Coastguard Worker NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:[self defaultVideoCodecSetting]]; 201*d9f75844SAndroid Build Coastguard Worker#endif 202*d9f75844SAndroid Build Coastguard Worker 203*d9f75844SAndroid Build Coastguard Worker [ARDSettingsStore setDefaultsForVideoResolution:[self defaultVideoResolutionSetting] 204*d9f75844SAndroid Build Coastguard Worker videoCodec:codecData 205*d9f75844SAndroid Build Coastguard Worker bitrate:nil 206*d9f75844SAndroid Build Coastguard Worker audioOnly:NO 207*d9f75844SAndroid Build Coastguard Worker createAecDump:NO 208*d9f75844SAndroid Build Coastguard Worker useManualAudioConfig:YES]; 209*d9f75844SAndroid Build Coastguard Worker} 210*d9f75844SAndroid Build Coastguard Worker@end 211*d9f75844SAndroid Build Coastguard WorkerNS_ASSUME_NONNULL_END 212