2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
14 KiB

  1. //
  2. // SCCameraTweaks.m
  3. // Snapchat
  4. //
  5. // Created by Liu Liu on 10/4/16.
  6. // Copyright © 2016 Snapchat, Inc. All rights reserved.
  7. //
  8. #import "SCCameraTweaks.h"
  9. #import "SCManagedCapturePreviewLayerController.h"
  10. #import <SCFoundation/SCDeviceName.h>
  11. #import <SCFoundation/SCZeroDependencyExperiments.h>
  12. #import <SCTweakAdditions/SCTweakDefines.h>
  13. SCManagedCaptureDeviceZoomHandlerType SCCameraTweaksDeviceZoomHandlerStrategy(void)
  14. {
  15. NSNumber *strategyNumber = SCTweakValueWithHalt(
  16. @"Camera", @"Core Camera", @"Zoom Strategy",
  17. @(SCIsMasterBuild() ? SCManagedCaptureDeviceLinearInterpolation : SCManagedCaptureDeviceDefaultZoom), (@{
  18. @(SCManagedCaptureDeviceDefaultZoom) : @"Default",
  19. @(SCManagedCaptureDeviceSavitzkyGolayFilter) : @"Savitzky-Golay Filter",
  20. @(SCManagedCaptureDeviceLinearInterpolation) : @"Linear Interpolation"
  21. }));
  22. return (SCManagedCaptureDeviceZoomHandlerType)[strategyNumber integerValue];
  23. }
  24. BOOL SCCameraTweaksEnableFaceDetectionFocus(SCManagedCaptureDevicePosition captureDevicePosition)
  25. {
  26. SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO);
  27. SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO);
  28. BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront);
  29. BOOL isEnabled = NO;
  30. SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy();
  31. switch (option) {
  32. case SCCameraFaceFocusModeStrategyTypeABTest:
  33. if (isFrontCamera) {
  34. isEnabled = SCExperimentWithFaceDetectionFocusFrontCameraEnabled();
  35. } else {
  36. isEnabled = SCExperimentWithFaceDetectionFocusBackCameraEnabled();
  37. }
  38. break;
  39. case SCCameraFaceFocusModeStrategyTypeDisabled:
  40. isEnabled = NO;
  41. break;
  42. case SCCameraFaceFocusModeStrategyTypeOffByDefault:
  43. case SCCameraFaceFocusModeStrategyTypeOnByDefault:
  44. isEnabled = YES;
  45. break;
  46. }
  47. return isEnabled;
  48. }
  49. BOOL SCCameraTweaksTurnOnFaceDetectionFocusByDefault(SCManagedCaptureDevicePosition captureDevicePosition)
  50. {
  51. SC_GUARD_ELSE_RETURN_VALUE([SCDeviceName isIphone], NO);
  52. SC_GUARD_ELSE_RETURN_VALUE(captureDevicePosition != SCManagedCaptureDevicePositionBackDualCamera, NO);
  53. BOOL isFrontCamera = (captureDevicePosition == SCManagedCaptureDevicePositionFront);
  54. BOOL isOnByDefault = NO;
  55. SCCameraFaceFocusModeStrategyType option = SCCameraTweaksFaceFocusStrategy();
  56. switch (option) {
  57. case SCCameraFaceFocusModeStrategyTypeABTest:
  58. if (isFrontCamera) {
  59. isOnByDefault = SCExperimentWithFaceDetectionFocusFrontCameraOnByDefault();
  60. } else {
  61. isOnByDefault = SCExperimentWithFaceDetectionFocusBackCameraOnByDefault();
  62. }
  63. break;
  64. case SCCameraFaceFocusModeStrategyTypeDisabled:
  65. case SCCameraFaceFocusModeStrategyTypeOffByDefault:
  66. isOnByDefault = NO;
  67. break;
  68. case SCCameraFaceFocusModeStrategyTypeOnByDefault:
  69. isOnByDefault = YES;
  70. break;
  71. }
  72. return isOnByDefault;
  73. }
  74. SCCameraFaceFocusDetectionMethodType SCCameraFaceFocusDetectionMethod()
  75. {
  76. static SCCameraFaceFocusDetectionMethodType detectionMethodType;
  77. static dispatch_once_t onceToken;
  78. dispatch_once(&onceToken, ^{
  79. SCCameraFaceFocusDetectionMethodType option = SCCameraTweaksFaceFocusDetectionMethodType();
  80. switch (option) {
  81. case SCCameraFaceFocusDetectionMethodTypeABTest: {
  82. // Check the validity of AB value.
  83. NSUInteger experimentValue = SCExperimentWithFaceDetectionFocusDetectionMethod();
  84. if (experimentValue >= SCCameraFaceFocusDetectionMethodTypeCIDetector &&
  85. experimentValue <= SCCameraFaceFocusDetectionMethodTypeAVMetadata) {
  86. detectionMethodType = experimentValue;
  87. } else {
  88. // Use CIDetector by default.
  89. detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector;
  90. }
  91. } break;
  92. case SCCameraFaceFocusDetectionMethodTypeAVMetadata:
  93. detectionMethodType = SCCameraFaceFocusDetectionMethodTypeAVMetadata;
  94. break;
  95. case SCCameraFaceFocusDetectionMethodTypeCIDetector:
  96. detectionMethodType = SCCameraFaceFocusDetectionMethodTypeCIDetector;
  97. break;
  98. }
  99. });
  100. return detectionMethodType;
  101. }
  102. CGFloat SCCameraFaceFocusMinFaceSize(void)
  103. {
  104. static CGFloat minFaceSize;
  105. static dispatch_once_t onceToken;
  106. dispatch_once(&onceToken, ^{
  107. if (SCCameraTweaksFaceFocusMinFaceSizeRespectABTesting()) {
  108. minFaceSize = (CGFloat)SCExperimentWithFaceDetectionMinFaceSize();
  109. } else {
  110. minFaceSize = SCCameraTweaksFaceFocusMinFaceSizeValue();
  111. }
  112. if (minFaceSize < 0.01 || minFaceSize > 0.5) {
  113. minFaceSize = 0.25; // Default value is 0.25
  114. }
  115. });
  116. return minFaceSize;
  117. }
  118. BOOL SCCameraTweaksEnableCaptureKeepRecordedVideo(void)
  119. {
  120. static BOOL enableCaptureKeepRecordedVideo;
  121. static dispatch_once_t onceToken;
  122. dispatch_once(&onceToken, ^{
  123. switch (SCCameraTweaksEnableCaptureKeepRecordedVideoStrategy()) {
  124. case SCCameraTweaksStrategyOverrideToYes: {
  125. enableCaptureKeepRecordedVideo = YES;
  126. break;
  127. }
  128. case SCCameraTweaksStrategyOverrideToNo: {
  129. enableCaptureKeepRecordedVideo = NO;
  130. break;
  131. }
  132. case SCCameraTweaksStrategyFollowABTest: {
  133. enableCaptureKeepRecordedVideo = SCExperimentWithCaptureKeepRecordedVideo();
  134. break;
  135. }
  136. default: {
  137. enableCaptureKeepRecordedVideo = NO;
  138. break;
  139. }
  140. }
  141. });
  142. return enableCaptureKeepRecordedVideo;
  143. }
  144. static inline SCCameraTweaksStrategyType SCCameraTweaksBlackCameraRecoveryStrategy(void)
  145. {
  146. NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Black Camera Recovery",
  147. (id) @(SCCameraTweaksStrategyFollowABTest), (@{
  148. @(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
  149. @(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
  150. @(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
  151. }));
  152. return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
  153. }
  154. BOOL SCCameraTweaksBlackCameraRecoveryEnabled(void)
  155. {
  156. static BOOL enabled;
  157. static dispatch_once_t onceToken;
  158. dispatch_once(&onceToken, ^{
  159. switch (SCCameraTweaksBlackCameraRecoveryStrategy()) {
  160. case SCCameraTweaksStrategyOverrideToYes:
  161. enabled = YES;
  162. break;
  163. case SCCameraTweaksStrategyOverrideToNo:
  164. enabled = NO;
  165. break;
  166. case SCCameraTweaksStrategyFollowABTest:
  167. enabled = SCExperimentWithBlackCameraRecovery();
  168. break;
  169. default:
  170. enabled = NO;
  171. break;
  172. }
  173. });
  174. return enabled;
  175. }
  176. static inline SCCameraTweaksStrategyType SCCameraTweaksMicrophoneNotificationStrategy(void)
  177. {
  178. NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Mic Notification",
  179. (id) @(SCCameraTweaksStrategyFollowABTest), (@{
  180. @(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
  181. @(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
  182. @(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
  183. }));
  184. return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
  185. }
  186. BOOL SCCameraTweaksMicPermissionEnabled(void)
  187. {
  188. static BOOL enabled;
  189. static dispatch_once_t onceToken;
  190. dispatch_once(&onceToken, ^{
  191. switch (SCCameraTweaksMicrophoneNotificationStrategy()) {
  192. case SCCameraTweaksStrategyOverrideToYes:
  193. enabled = YES;
  194. break;
  195. case SCCameraTweaksStrategyOverrideToNo:
  196. enabled = NO;
  197. break;
  198. case SCCameraTweaksStrategyFollowABTest:
  199. enabled = SCExperimentWithMicrophonePermissionNotificationEnabled();
  200. break;
  201. default:
  202. enabled = NO;
  203. break;
  204. }
  205. });
  206. return enabled;
  207. }
  208. SCCameraHandsFreeModeType SCCameraTweaksHandsFreeMode(void)
  209. {
  210. static SCCameraHandsFreeModeType handsFreeModeType;
  211. static dispatch_once_t onceToken;
  212. dispatch_once(&onceToken, ^{
  213. SCCameraHandsFreeModeType option = SCCameraTweaksHandsFreeModeType();
  214. switch (option) {
  215. case SCCameraHandsFreeModeTypeDisabled:
  216. handsFreeModeType = SCCameraHandsFreeModeTypeDisabled;
  217. break;
  218. case SCCameraHandsFreeModeTypeMainOnly:
  219. handsFreeModeType = SCCameraHandsFreeModeTypeMainOnly;
  220. break;
  221. case SCCameraHandsFreeModeTypeChatMoveCaptureButton:
  222. handsFreeModeType = SCCameraHandsFreeModeTypeChatMoveCaptureButton;
  223. break;
  224. case SCCameraHandsFreeModeTypeMainAndChat:
  225. handsFreeModeType = SCCameraHandsFreeModeTypeMainAndChat;
  226. break;
  227. case SCCameraHandsFreeModeTypeLeftOfCapture:
  228. handsFreeModeType = SCCameraHandsFreeModeTypeLeftOfCapture;
  229. break;
  230. case SCCameraHandsFreeModeTypeABTest:
  231. default:
  232. handsFreeModeType = SCExperimentWithHandsFreeMode();
  233. break;
  234. }
  235. });
  236. return handsFreeModeType;
  237. }
  238. BOOL SCCameraTweaksEnableHandsFreeXToCancel(void)
  239. {
  240. static BOOL enableHandsFreeXToCancel;
  241. static dispatch_once_t onceToken;
  242. dispatch_once(&onceToken, ^{
  243. switch (SCCameraTweaksEnableHandsFreeXToCancelStrategy()) {
  244. case SCCameraTweaksStrategyOverrideToYes: {
  245. enableHandsFreeXToCancel = YES;
  246. break;
  247. }
  248. case SCCameraTweaksStrategyOverrideToNo: {
  249. enableHandsFreeXToCancel = NO;
  250. break;
  251. }
  252. case SCCameraTweaksStrategyFollowABTest: {
  253. enableHandsFreeXToCancel = SCExperimentWithHandsFreeXToCancel();
  254. break;
  255. }
  256. default: {
  257. enableHandsFreeXToCancel = NO;
  258. break;
  259. }
  260. }
  261. });
  262. return enableHandsFreeXToCancel;
  263. }
  264. BOOL SCCameraTweaksEnableShortPreviewTransitionAnimationDuration(void)
  265. {
  266. static BOOL enableShortPreviewTransitionAnimationDuration;
  267. static dispatch_once_t onceToken;
  268. dispatch_once(&onceToken, ^{
  269. switch (SCCameraTweaksPreviewTransitionAnimationDurationStrategy()) {
  270. case SCCameraTweaksStrategyOverrideToYes: {
  271. enableShortPreviewTransitionAnimationDuration = YES;
  272. break;
  273. }
  274. case SCCameraTweaksStrategyOverrideToNo: {
  275. enableShortPreviewTransitionAnimationDuration = NO;
  276. break;
  277. }
  278. case SCCameraTweaksStrategyFollowABTest: {
  279. enableShortPreviewTransitionAnimationDuration = SCExperimentWithShortPreviewTransitionAnimationDuration();
  280. break;
  281. }
  282. default: {
  283. enableShortPreviewTransitionAnimationDuration = YES;
  284. break;
  285. }
  286. }
  287. });
  288. return enableShortPreviewTransitionAnimationDuration;
  289. }
  290. BOOL SCCameraTweaksEnablePreviewPresenterFastPreview(void)
  291. {
  292. static BOOL enablePreviewPresenterFastPreview;
  293. static dispatch_once_t onceToken;
  294. dispatch_once(&onceToken, ^{
  295. switch (SCCameraTweaksPreviewPresenterFastPreviewStrategy()) {
  296. case SCCameraTweaksStrategyOverrideToYes: {
  297. enablePreviewPresenterFastPreview = YES;
  298. break;
  299. }
  300. case SCCameraTweaksStrategyOverrideToNo: {
  301. enablePreviewPresenterFastPreview = NO;
  302. break;
  303. }
  304. case SCCameraTweaksStrategyFollowABTest: {
  305. enablePreviewPresenterFastPreview = SCExperimentWithPreviewPresenterFastPreview();
  306. break;
  307. }
  308. default: {
  309. enablePreviewPresenterFastPreview = NO;
  310. break;
  311. }
  312. }
  313. });
  314. return enablePreviewPresenterFastPreview;
  315. }
  316. BOOL SCCameraTweaksEnableCaptureSharePerformer(void)
  317. {
  318. static BOOL enableCaptureSharePerformer;
  319. static dispatch_once_t onceToken;
  320. dispatch_once(&onceToken, ^{
  321. switch (SCCameraTweaksEnableCaptureSharePerformerStrategy()) {
  322. case SCCameraTweaksStrategyOverrideToYes: {
  323. enableCaptureSharePerformer = YES;
  324. break;
  325. }
  326. case SCCameraTweaksStrategyOverrideToNo: {
  327. enableCaptureSharePerformer = NO;
  328. break;
  329. }
  330. case SCCameraTweaksStrategyFollowABTest: {
  331. enableCaptureSharePerformer = SCExperimentWithCaptureSharePerformer();
  332. break;
  333. }
  334. default: {
  335. enableCaptureSharePerformer = NO;
  336. break;
  337. }
  338. }
  339. });
  340. return enableCaptureSharePerformer;
  341. }
  342. static inline SCCameraTweaksStrategyType SCCameraTweaksSessionLightWeightFixStrategy(void)
  343. {
  344. NSNumber *strategy = SCTweakValueWithHalt(@"Camera", @"Core Camera", @"Light-weight Session Fix",
  345. (id) @(SCCameraTweaksStrategyFollowABTest), (@{
  346. @(SCCameraTweaksStrategyFollowABTest) : @"Respect A/B testing",
  347. @(SCCameraTweaksStrategyOverrideToYes) : @"Override to YES",
  348. @(SCCameraTweaksStrategyOverrideToNo) : @"Override to NO"
  349. }));
  350. return (SCCameraTweaksStrategyType)[strategy unsignedIntegerValue];
  351. }
  352. BOOL SCCameraTweaksSessionLightWeightFixEnabled(void)
  353. {
  354. static BOOL enabled;
  355. static dispatch_once_t onceToken;
  356. dispatch_once(&onceToken, ^{
  357. switch (SCCameraTweaksSessionLightWeightFixStrategy()) {
  358. case SCCameraTweaksStrategyOverrideToYes:
  359. enabled = YES;
  360. break;
  361. case SCCameraTweaksStrategyOverrideToNo:
  362. enabled = NO;
  363. break;
  364. case SCCameraTweaksStrategyFollowABTest:
  365. enabled = SCExperimentWithSessionLightWeightFix();
  366. break;
  367. default:
  368. enabled = NO;
  369. break;
  370. }
  371. });
  372. return enabled;
  373. }