Source-SCCamera/Logging/SCLogger+Camera.m

304 lines
14 KiB
Objective-C

//
// SCLogger+Camera.m
// Snapchat
//
// Created by Derek Peirce on 5/8/17.
// Copyright © 2017 Snapchat, Inc. All rights reserved.
//
#import "SCLogger+Camera.h"
#import "SCCameraTweaks.h"
#import <SCFoundation/SCTrace.h>
#import <SCFoundation/SCTraceODPCompatible.h>
#import <SCLogger/SCCameraMetrics+CameraCreationDelay.h>
#import <SCLogger/SCCameraMetrics.h>
#import <SCLogger/SCLogger+Performance.h>
#import <objc/runtime.h>
@implementation SCLogger (Camera)
@dynamic cameraCreationDelayLoggingStatus;
- (NSNumber *)cameraCreationDelayLoggingStatus
{
return objc_getAssociatedObject(self, @selector(cameraCreationDelayLoggingStatus));
}
- (void)setCameraCreationDelayLoggingStatus:(NSNumber *)status
{
objc_setAssociatedObject(self, @selector(cameraCreationDelayLoggingStatus), status,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)shouldLogCameraCreationDelay
{
return [[self cameraCreationDelayLoggingStatus] intValue] != CAMERA_CREATION_DELAY_LOGGING_END;
}
- (void)logCameraCreationDelayEnd
{
if ([[self cameraCreationDelayLoggingStatus] intValue] == CAMERA_CREATION_DELAY_LOGGINT_LAST_STEP) {
SCTraceSignPostEndForMetrics(kSCSignPostCameraCreationDelay, 0, 0, 0, 0);
[self setCameraCreationDelayLoggingStatus:@(CAMERA_CREATION_DELAY_LOGGING_END)];
} else {
[self setCameraCreationDelayLoggingStatus:@(CAMERA_CREATION_DELAY_LOGGINT_LAST_STEP)];
}
}
- (void)logCameraCreationStartWithMethod:(SCCameraRecordingMethod)method
lensesEnabled:(BOOL)lensesEnabled
activeLensId:(NSString *)activeLensId
captureSessionId:(NSString *)captureSessionId
{
NSMutableDictionary *parameters = [@{
@"lens_ui_enabled" : @(lensesEnabled),
@"analytics_version" : kSCCameraDelayEventVersion,
@"method" : @(method),
} mutableCopy];
if (lensesEnabled && activeLensId) {
[parameters setObject:activeLensId forKey:@"lens_id"];
}
if (captureSessionId) {
[parameters setObject:captureSessionId forKey:@"capture_session_id"];
}
[self setCameraCreationDelayLoggingStatus:@(CAMERA_CREATION_DELAY_LOGGING_START)];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraCreationDelay];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraRecordingGestureFinished];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraPreCaptureOperationRequested];
[[SCLogger sharedInstance] logTimedEventStart:kSCCameraCaptureDelayEvent
uniqueId:@""
isUniqueEvent:NO
parameters:parameters
shouldLogStartTime:YES];
}
- (void)logCameraExposureAdjustmentDelayStart
{
[[SCLogger sharedInstance] logTimedEventStart:kSCCameraExposureAdjustmentDelay
uniqueId:@""
isUniqueEvent:NO
parameters:nil
shouldLogStartTime:YES];
}
- (void)logCameraExposureAdjustmentDelayEndWithStrategy:(NSString *)strategy
{
[[SCLogger sharedInstance] logTimedEventEnd:kSCCameraExposureAdjustmentDelay
uniqueId:@""
parameters:@{
@"strategy" : strategy
}];
}
- (void)logCameraCaptureRecordingGestureFinishedAtTime:(CFTimeInterval)endRecordingTime
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraRecordingGestureFinished];
[[SCLogger sharedInstance]
updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
update:^(NSMutableDictionary *startParameters) {
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
NSNumber *recordStartTime =
(NSNumber *)eventParameters[kSCCameraSubmetricsPreCaptureOperationFinished];
CFTimeInterval endRecordingTimeOffset =
endRecordingTime -
[startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventTimeKey] doubleValue];
if (recordStartTime) {
CFTimeInterval timeDisplacement =
([recordStartTime doubleValue] / 1000.0) - endRecordingTimeOffset;
[eventParameters setObject:@(timeDisplacement)
forKey:SCPerformanceMetricsKey.kSCLoggerStartEventTimeAdjustmentKey];
}
[self addSplitPoint:kSCCameraSubmetricsRecordingGestureFinished
atTime:endRecordingTime
toEvent:startParameters];
}];
}
- (void)logStillImageCaptureApi:(NSString *)api
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreCaptureOperationRequested];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraPreCaptureOperationFinished];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraCaptureContentReady];
CFTimeInterval requestTime = CACurrentMediaTime();
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
update:^(NSMutableDictionary *startParameters) {
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
[eventParameters setObject:api forKey:@"api_type"];
[eventParameters setObject:@(1) forKey:@"camera_api_level"];
[self addSplitPoint:@"PRE_CAPTURE_OPERATION_REQUESTED"
atTime:requestTime
toEvent:startParameters];
}];
}
- (void)logPreCaptureOperationRequestedAt:(CFTimeInterval)requestTime
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreCaptureOperationRequested];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraPreCaptureOperationFinished];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraCaptureContentReady];
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
splitPoint:kSCCameraSubmetricsPreCaptureOperationRequested
time:requestTime];
}
- (void)logPreCaptureOperationFinishedAt:(CFTimeInterval)time
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreCaptureOperationFinished];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraPreviewPlayerReady];
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
splitPoint:kSCCameraSubmetricsPreCaptureOperationFinished
time:time];
}
- (void)logCameraCaptureFinishedWithDuration:(CFTimeInterval)duration
{
[[SCLogger sharedInstance]
updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
update:^(NSMutableDictionary *startParameters) {
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
[eventParameters setObject:@(SCTimeInMillisecond(duration)) forKey:@"content_duration"];
}];
}
- (void)logCameraCaptureContentReady
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraCaptureContentReady];
[[SCLogger sharedInstance] updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
splitPoint:kSCCameraSubmetricsCameraCaptureContentReady];
}
- (void)logPreviewFinishedPreparation
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreviewFinishPreparation];
[self logCameraCreationDelaySubMetricsStartWithSignCode:kSCSignPostCameraPreviewAnimationFinish];
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
splitPoint:kSCCameraSubmetricsPreviewFinishPreparation];
}
- (void)logPreviewDisplayedForImage:(BOOL)isImage
{
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreviewLayoutReady];
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent uniqueId:@"" splitPoint:kSCCameraSubmetricsPreviewLayoutReady];
}
- (void)logPreviewAnimationComplete:(BOOL)isImage
{
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent
uniqueId:@""
splitPoint:kSCCameraSubmetricsPreviewAnimationFinish];
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreviewAnimationFinish];
[self logCameraCreationDelayEnd];
[self conditionallyLogTimedEventEnd:kSCCameraCaptureDelayEvent
uniqueId:@""
parameters:@{
@"type" : isImage ? @"image" : @"video",
}
shouldLog:^BOOL(NSDictionary *startParameters) {
// For video, PREVIEW_PLAYER_READY and PREVIEW_ANIMATION_FINISH can happen in either
// order. So here we check for existence of this key, and end timer if the other
// event have happened.
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
return eventParameters[kSCCameraSubmetricsPreviewPlayerReady] != nil;
}];
}
- (void)logPreviewFirstFramePlayed:(BOOL)isImage
{
[self updateLogTimedEvent:kSCCameraCaptureDelayEvent uniqueId:@"" splitPoint:kSCCameraSubmetricsPreviewPlayerReady];
[self logCameraCreationDelaySubMetricsEndWithSignCode:kSCSignPostCameraPreviewPlayerReady];
[self logCameraCreationDelayEnd];
[self conditionallyLogTimedEventEnd:kSCCameraCaptureDelayEvent
uniqueId:@""
parameters:@{
@"type" : isImage ? @"image" : @"video",
}
shouldLog:^BOOL(NSDictionary *startParameters) {
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
// See the comment above for PREVIEW_PLAYER_READY and PREVIEW_ANIMATION_FINISH.
return eventParameters[kSCCameraSubmetricsPreviewAnimationFinish] != nil;
}];
}
- (void)cancelCameraCreationEvent
{
[self cancelLogTimedEvent:kSCCameraCaptureDelayEvent uniqueId:@""];
}
- (void)logRecordingMayBeTooShortWithMethod:(SCCameraRecordingMethod)method
{
[[SCLogger sharedInstance] cancelLogTimedEvent:kSCCameraMetricsRecordingTooShort uniqueId:@""];
[[SCLogger sharedInstance] logTimedEventStart:kSCCameraMetricsRecordingTooShort
uniqueId:@""
isUniqueEvent:NO
parameters:@{
@"method" : @(method),
@"analytics_version" : kSCCameraRecordingTooShortVersion,
}
shouldLogStartTime:YES];
}
- (void)logRecordingWasTooShortWithFirstFrame:(CMTime)firstFrame
frontFacingCamera:(BOOL)isFrontFacing
cameraFlips:(NSInteger)cameraFlips
{
[self logTimedEventEnd:kSCCameraMetricsRecordingTooShort
uniqueId:@""
update:^(NSDictionary *startParameters, CFTimeInterval eventEndTime, CFTimeInterval adjustedTime) {
NSMutableDictionary *eventParameters =
startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventParametersKey];
if (CMTIME_IS_VALID(firstFrame)) {
CFTimeInterval startTime =
[startParameters[SCPerformanceMetricsKey.kSCLoggerStartEventTimeKey] doubleValue];
CFTimeInterval firstFrameRelative = CMTimeGetSeconds(firstFrame) - startTime;
[eventParameters setObject:@(firstFrameRelative) forKey:@"first_frame_s"];
}
[eventParameters setObject:@(isFrontFacing) forKey:@"is_front_facing"];
if (cameraFlips) {
[eventParameters setObject:@(cameraFlips > 0) forKey:@"has_camera_been_flipped"];
}
}];
}
- (void)logManagedCapturerSettingFailure:(NSString *)settingTask error:(NSError *)error
{
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
parameters[@"setting_task"] = settingTask;
if (error) {
parameters[@"setting error"] = error;
}
[[SCLogger sharedInstance] logTimedEventEnd:kSCCameraManagedCaptureSettingFailure
uniqueId:@""
parameters:parameters];
}
- (void)logCameraCreationDelaySubMetricsStartWithSignCode:(kSCSignPostCodeEnum)signPostCode
{
if ([self shouldLogCameraCreationDelay]) {
SCTraceSignPostStartForMetrics(signPostCode, 0, 0, 0, 0);
}
}
- (void)logCameraCreationDelaySubMetricsEndWithSignCode:(kSCSignPostCodeEnum)signPostCode
{
if ([self shouldLogCameraCreationDelay]) {
SCTraceSignPostEndForMetrics(signPostCode, 0, 0, 0, 0);
}
}
@end