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.

304 lines
14 KiB

  1. //
  2. // SCCoreCameraLogger.m
  3. // Snapchat
  4. //
  5. // Created by Chao Pang on 3/6/18.
  6. //
  7. #import "SCCoreCameraLogger.h"
  8. #import <BlizzardSchema/SCAEvents.h>
  9. #import <SCFoundation/SCQueuePerformer.h>
  10. #import <SCGhostToSnappable/SCGhostToSnappableSignal.h>
  11. #import <SCLogger/SCCameraMetrics+CameraCreationDelay.h>
  12. static const char *kSCCoreCameraLoggerQueueLabel = "com.snapchat.core-camera-logger-queue";
  13. NSString *const kSCCameraCreationDelayEventStartTimeKey = @"start_time";
  14. NSString *const kSCCameraCreationDelayEventStartTimeAdjustmentKey = @"start_time_adjustment";
  15. NSString *const kSCCameraCreationDelayEventEndTimeKey = @"end_time";
  16. NSString *const kSCCameraCreationDelayEventCaptureSessionIdKey = @"capture_session_id";
  17. NSString *const kSCCameraCreationDelayEventFilterLensIdKey = @"filter_lens_id";
  18. NSString *const kSCCameraCreationDelayEventNightModeDetectedKey = @"night_mode_detected";
  19. NSString *const kSCCameraCreationDelayEventNightModeActiveKey = @"night_mode_active";
  20. NSString *const kSCCameraCreationDelayEventCameraApiKey = @"camera_api";
  21. NSString *const kSCCameraCreationDelayEventCameraLevelKey = @"camera_level";
  22. NSString *const kSCCameraCreationDelayEventCameraPositionKey = @"camera_position";
  23. NSString *const kSCCameraCreationDelayEventCameraOpenSourceKey = @"camera_open_source";
  24. NSString *const kSCCameraCreationDelayEventContentDurationKey = @"content_duration";
  25. NSString *const kSCCameraCreationDelayEventMediaTypeKey = @"media_type";
  26. NSString *const kSCCameraCreationDelayEventStartTypeKey = @"start_type";
  27. NSString *const kSCCameraCreationDelayEventStartSubTypeKey = @"start_sub_type";
  28. NSString *const kSCCameraCreationDelayEventAnalyticsVersion = @"ios_v1";
  29. static inline NSUInteger SCTimeToMS(CFTimeInterval time)
  30. {
  31. return (NSUInteger)(time * 1000);
  32. }
  33. static NSString *SCDictionaryToJSONString(NSDictionary *dictionary)
  34. {
  35. NSData *dictData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
  36. return [[NSString alloc] initWithData:dictData encoding:NSUTF8StringEncoding];
  37. }
  38. @implementation SCCoreCameraLogger {
  39. SCQueuePerformer *_performer;
  40. NSMutableDictionary *_cameraCreationDelayParameters;
  41. NSMutableDictionary *_cameraCreationDelaySplits;
  42. }
  43. - (instancetype)init
  44. {
  45. self = [super init];
  46. if (self) {
  47. _cameraCreationDelayParameters = [NSMutableDictionary dictionary];
  48. _cameraCreationDelaySplits = [NSMutableDictionary dictionary];
  49. _performer = [[SCQueuePerformer alloc] initWithLabel:kSCCoreCameraLoggerQueueLabel
  50. qualityOfService:QOS_CLASS_UNSPECIFIED
  51. queueType:DISPATCH_QUEUE_SERIAL
  52. context:SCQueuePerformerContextCoreCamera];
  53. }
  54. return self;
  55. }
  56. + (instancetype)sharedInstance
  57. {
  58. static SCCoreCameraLogger *sharedInstance;
  59. static dispatch_once_t onceToken;
  60. dispatch_once(&onceToken, ^{
  61. sharedInstance = [[SCCoreCameraLogger alloc] init];
  62. });
  63. return sharedInstance;
  64. }
  65. // Camera creation delay metrics
  66. - (void)logCameraCreationDelayEventStartWithCaptureSessionId:(NSString *)captureSessionId
  67. filterLensId:(NSString *)filterLensId
  68. underLowLightCondition:(BOOL)underLowLightCondition
  69. isNightModeActive:(BOOL)isNightModeActive
  70. isBackCamera:(BOOL)isBackCamera
  71. isMainCamera:(BOOL)isMainCamera
  72. {
  73. CFTimeInterval startTime = CACurrentMediaTime();
  74. [_performer perform:^{
  75. [_cameraCreationDelayParameters removeAllObjects];
  76. [_cameraCreationDelaySplits removeAllObjects];
  77. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeKey] = @(startTime);
  78. _cameraCreationDelayParameters[kSCCameraCreationDelayEventCaptureSessionIdKey] = captureSessionId ?: @"null";
  79. _cameraCreationDelayParameters[kSCCameraCreationDelayEventFilterLensIdKey] = filterLensId ?: @"null";
  80. _cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeDetectedKey] = @(underLowLightCondition);
  81. _cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeActiveKey] = @(isNightModeActive);
  82. _cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraPositionKey] =
  83. isBackCamera ? @"back" : @"front";
  84. _cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraOpenSourceKey] =
  85. isMainCamera ? @"main_camera" : @"reply_camera";
  86. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTypeKey] = SCLaunchType() ?: @"null";
  87. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartSubTypeKey] = SCLaunchSubType() ?: @"null";
  88. }];
  89. }
  90. - (void)logCameraCreationDelaySplitPointRecordingGestureFinished
  91. {
  92. CFTimeInterval time = CACurrentMediaTime();
  93. [_performer perform:^{
  94. CFTimeInterval endRecordingTimeOffset =
  95. time - [_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeKey] doubleValue];
  96. NSNumber *recordStartTimeMillis =
  97. (NSNumber *)_cameraCreationDelaySplits[kSCCameraSubmetricsPreCaptureOperationFinished];
  98. if (recordStartTimeMillis) {
  99. CFTimeInterval timeDisplacement = ([recordStartTimeMillis doubleValue] / 1000.0) - endRecordingTimeOffset;
  100. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeAdjustmentKey] = @(timeDisplacement);
  101. }
  102. [self _addSplitPointForKey:kSCCameraSubmetricsRecordingGestureFinished atTime:time];
  103. }];
  104. }
  105. - (void)logCameraCreationDelaySplitPointStillImageCaptureApi:(NSString *)api
  106. {
  107. CFTimeInterval time = CACurrentMediaTime();
  108. [_performer perform:^{
  109. if (api) {
  110. _cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraApiKey] = api;
  111. }
  112. [self _addSplitPointForKey:kSCCameraSubmetricsPreCaptureOperationRequested atTime:time];
  113. }];
  114. }
  115. - (void)logCameraCreationDelaySplitPointPreCaptureOperationRequested
  116. {
  117. CFTimeInterval time = CACurrentMediaTime();
  118. [_performer perform:^{
  119. [self _addSplitPointForKey:kSCCameraSubmetricsPreCaptureOperationRequested atTime:time];
  120. }];
  121. }
  122. - (void)logCameraCreationDelaySplitPointPreCaptureOperationFinishedAt:(CFTimeInterval)time
  123. {
  124. [_performer perform:^{
  125. [self _addSplitPointForKey:kSCCameraSubmetricsPreCaptureOperationFinished atTime:time];
  126. }];
  127. }
  128. - (void)updatedCameraCreationDelayWithContentDuration:(CFTimeInterval)duration
  129. {
  130. [_performer perform:^{
  131. _cameraCreationDelayParameters[kSCCameraCreationDelayEventContentDurationKey] = @(SCTimeToMS(duration));
  132. }];
  133. }
  134. - (void)logCameraCreationDelaySplitPointCameraCaptureContentReady
  135. {
  136. CFTimeInterval time = CACurrentMediaTime();
  137. [_performer perform:^{
  138. [self _addSplitPointForKey:kSCCameraSubmetricsCameraCaptureContentReady atTime:time];
  139. }];
  140. }
  141. - (void)logCameraCreationDelaySplitPointPreviewFinishedPreparation
  142. {
  143. CFTimeInterval time = CACurrentMediaTime();
  144. [_performer perform:^{
  145. [self _addSplitPointForKey:kSCCameraSubmetricsCameraCaptureContentReady atTime:time];
  146. }];
  147. }
  148. - (void)logCameraCreationDelaySplitPointPreviewDisplayedForImage:(BOOL)isImage
  149. {
  150. CFTimeInterval time = CACurrentMediaTime();
  151. [_performer perform:^{
  152. [self _addSplitPointForKey:kSCCameraSubmetricsPreviewLayoutReady atTime:time];
  153. }];
  154. }
  155. - (void)logCameraCreationDelaySplitPointPreviewAnimationComplete:(BOOL)isImage
  156. {
  157. CFTimeInterval time = CACurrentMediaTime();
  158. [_performer perform:^{
  159. [self _addSplitPointForKey:kSCCameraSubmetricsPreviewAnimationFinish atTime:time];
  160. if (_cameraCreationDelaySplits[kSCCameraSubmetricsPreviewPlayerReady]) {
  161. [self _completeLogCameraCreationDelayEventWithIsImage:isImage atTime:time];
  162. }
  163. }];
  164. }
  165. - (void)logCameraCreationDelaySplitPointPreviewFirstFramePlayed:(BOOL)isImage
  166. {
  167. CFTimeInterval time = CACurrentMediaTime();
  168. [_performer perform:^{
  169. [self _addSplitPointForKey:kSCCameraSubmetricsPreviewPlayerReady atTime:time];
  170. if (_cameraCreationDelaySplits[kSCCameraSubmetricsPreviewAnimationFinish]) {
  171. [self _completeLogCameraCreationDelayEventWithIsImage:isImage atTime:time];
  172. }
  173. }];
  174. }
  175. - (void)cancelCameraCreationDelayEvent
  176. {
  177. [_performer perform:^{
  178. [_cameraCreationDelayParameters removeAllObjects];
  179. [_cameraCreationDelaySplits removeAllObjects];
  180. }];
  181. }
  182. #pragma - Private methods
  183. - (void)_completeLogCameraCreationDelayEventWithIsImage:(BOOL)isImage atTime:(CFTimeInterval)time
  184. {
  185. SCAssertPerformer(_performer);
  186. if (_cameraCreationDelayParameters[kSCCameraCreationDelayEventCaptureSessionIdKey]) {
  187. _cameraCreationDelayParameters[kSCCameraCreationDelayEventMediaTypeKey] = isImage ? @"image" : @"video";
  188. _cameraCreationDelayParameters[kSCCameraCreationDelayEventEndTimeKey] = @(time);
  189. [self _logCameraCreationDelayBlizzardEvent];
  190. }
  191. [_cameraCreationDelayParameters removeAllObjects];
  192. [_cameraCreationDelaySplits removeAllObjects];
  193. }
  194. - (void)_addSplitPointForKey:(NSString *)key atTime:(CFTimeInterval)time
  195. {
  196. SCAssertPerformer(_performer);
  197. if (key) {
  198. CFTimeInterval timeOffset =
  199. time - [_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeKey] doubleValue];
  200. NSNumber *timeAdjustment =
  201. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeAdjustmentKey] ?: @(0);
  202. _cameraCreationDelaySplits[key] = @(SCTimeToMS(timeOffset + [timeAdjustment doubleValue]));
  203. }
  204. }
  205. - (void)_logCameraCreationDelayBlizzardEvent
  206. {
  207. SCAssertPerformer(_performer);
  208. SCASharedCameraMetricParams *sharedCameraMetricsParams = [[SCASharedCameraMetricParams alloc] init];
  209. [sharedCameraMetricsParams setAnalyticsVersion:kSCCameraCreationDelayEventAnalyticsVersion];
  210. NSString *mediaType = _cameraCreationDelayParameters[kSCCameraCreationDelayEventMediaTypeKey];
  211. if (mediaType) {
  212. if ([mediaType isEqualToString:@"image"]) {
  213. [sharedCameraMetricsParams setMediaType:SCAMediaType_IMAGE];
  214. } else if ([mediaType isEqualToString:@"video"]) {
  215. [sharedCameraMetricsParams setMediaType:SCAMediaType_VIDEO];
  216. }
  217. }
  218. if (_cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeDetectedKey] &&
  219. _cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeActiveKey]) {
  220. BOOL isNightModeDetected =
  221. [_cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeDetectedKey] boolValue];
  222. BOOL isNightModeActive =
  223. [_cameraCreationDelayParameters[kSCCameraCreationDelayEventNightModeActiveKey] boolValue];
  224. if (!isNightModeDetected) {
  225. [sharedCameraMetricsParams setLowLightStatus:SCALowLightStatus_NOT_DETECTED];
  226. } else if (!isNightModeActive) {
  227. [sharedCameraMetricsParams setLowLightStatus:SCALowLightStatus_DETECTED];
  228. } else if (isNightModeActive) {
  229. [sharedCameraMetricsParams setLowLightStatus:SCALowLightStatus_ENABLED];
  230. }
  231. }
  232. [sharedCameraMetricsParams setPowerMode:[[NSProcessInfo processInfo] isLowPowerModeEnabled]
  233. ? @"LOW_POWER_MODE_ENABLED"
  234. : @"LOW_POWER_MODE_DISABLED"];
  235. [sharedCameraMetricsParams
  236. setFilterLensId:_cameraCreationDelayParameters[kSCCameraCreationDelayEventFilterLensIdKey] ?: @"null"];
  237. [sharedCameraMetricsParams
  238. setCaptureSessionId:_cameraCreationDelayParameters[kSCCameraCreationDelayEventCaptureSessionIdKey] ?: @"null"];
  239. [sharedCameraMetricsParams
  240. setCameraApi:_cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraApiKey] ?: @"null"];
  241. [sharedCameraMetricsParams
  242. setCameraPosition:_cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraPositionKey] ?: @"null"];
  243. [sharedCameraMetricsParams
  244. setCameraOpenSource:_cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraOpenSourceKey] ?: @"null"];
  245. [sharedCameraMetricsParams
  246. setCameraLevel:_cameraCreationDelayParameters[kSCCameraCreationDelayEventCameraLevelKey] ?: @"null"];
  247. [sharedCameraMetricsParams
  248. setStartType:_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTypeKey] ?: @"null"];
  249. [sharedCameraMetricsParams
  250. setStartSubType:_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartSubTypeKey] ?: @"null"];
  251. [sharedCameraMetricsParams setSplits:SCDictionaryToJSONString(_cameraCreationDelaySplits)];
  252. SCACameraSnapCreateDelay *creationDelay = [[SCACameraSnapCreateDelay alloc] init];
  253. if (_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeKey] &&
  254. _cameraCreationDelayParameters[kSCCameraCreationDelayEventEndTimeKey]) {
  255. double startTime = [_cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeKey] doubleValue];
  256. double endTime = [_cameraCreationDelayParameters[kSCCameraCreationDelayEventEndTimeKey] doubleValue];
  257. NSNumber *timeAdjustment =
  258. _cameraCreationDelayParameters[kSCCameraCreationDelayEventStartTimeAdjustmentKey] ?: @(0);
  259. [creationDelay setLatencyMillis:SCTimeToMS(endTime - startTime + [timeAdjustment doubleValue])];
  260. } else {
  261. [creationDelay setLatencyMillis:0];
  262. }
  263. if (_cameraCreationDelayParameters[kSCCameraCreationDelayEventContentDurationKey]) {
  264. [creationDelay
  265. setContentDurationMillis:SCTimeToMS(
  266. [_cameraCreationDelayParameters[kSCCameraCreationDelayEventContentDurationKey]
  267. doubleValue])];
  268. } else {
  269. [creationDelay setContentDurationMillis:0];
  270. }
  271. [creationDelay setSharedCameraMetricParams:sharedCameraMetricsParams];
  272. [[SCLogger sharedInstance] logUserTrackedEvent:creationDelay];
  273. }
  274. @end