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.

301 lines
13 KiB

  1. //
  2. // SCCaptureStateMachineContext.m
  3. // Snapchat
  4. //
  5. // Created by Lin Jia on 10/18/17.
  6. //
  7. //
  8. #import "SCCaptureStateMachineContext.h"
  9. #import "SCCaptureBaseState.h"
  10. #import "SCCaptureImageState.h"
  11. #import "SCCaptureImageWhileRecordingState.h"
  12. #import "SCCaptureInitializedState.h"
  13. #import "SCCaptureRecordingState.h"
  14. #import "SCCaptureResource.h"
  15. #import "SCCaptureRunningState.h"
  16. #import "SCCaptureScanningState.h"
  17. #import "SCCaptureStateMachineBookKeeper.h"
  18. #import "SCCaptureStateUtil.h"
  19. #import "SCCaptureUninitializedState.h"
  20. #import "SCCaptureWorker.h"
  21. #import "SCCapturerToken.h"
  22. #import "SCStateTransitionPayload.h"
  23. #import <SCAudio/SCAudioConfiguration.h>
  24. #import <SCFoundation/SCAssertWrapper.h>
  25. #import <SCFoundation/SCQueuePerformer.h>
  26. #import <SCFoundation/SCTrace.h>
  27. #import <SCLogger/SCCameraMetrics.h>
  28. #import <SCLogger/SCLogger+Performance.h>
  29. @interface SCCaptureStateMachineContext () <SCCaptureStateDelegate> {
  30. SCQueuePerformer *_queuePerformer;
  31. // Cache all the states.
  32. NSMutableDictionary<SCCaptureStateKey *, SCCaptureBaseState *> *_states;
  33. SCCaptureBaseState *_currentState;
  34. SCCaptureStateMachineBookKeeper *_bookKeeper;
  35. SCCaptureResource *_captureResource;
  36. }
  37. @end
  38. @implementation SCCaptureStateMachineContext
  39. - (instancetype)initWithResource:(SCCaptureResource *)resource
  40. {
  41. self = [super init];
  42. if (self) {
  43. SCAssert(resource, @"");
  44. SCAssert(resource.queuePerformer, @"");
  45. _captureResource = resource;
  46. _queuePerformer = resource.queuePerformer;
  47. _states = [[NSMutableDictionary<SCCaptureStateKey *, SCCaptureBaseState *> alloc] init];
  48. _bookKeeper = [[SCCaptureStateMachineBookKeeper alloc] init];
  49. [self _setCurrentState:SCCaptureUninitializedStateId payload:nil context:SCCapturerContext];
  50. }
  51. return self;
  52. }
  53. - (void)_setCurrentState:(SCCaptureStateMachineStateId)stateId
  54. payload:(SCStateTransitionPayload *)payload
  55. context:(NSString *)context
  56. {
  57. switch (stateId) {
  58. case SCCaptureUninitializedStateId:
  59. if (![_states objectForKey:@(stateId)]) {
  60. SCCaptureUninitializedState *uninitializedState =
  61. [[SCCaptureUninitializedState alloc] initWithPerformer:_queuePerformer
  62. bookKeeper:_bookKeeper
  63. delegate:self];
  64. [_states setObject:uninitializedState forKey:@(stateId)];
  65. }
  66. _currentState = [_states objectForKey:@(stateId)];
  67. break;
  68. case SCCaptureInitializedStateId:
  69. if (![_states objectForKey:@(stateId)]) {
  70. SCCaptureInitializedState *initializedState =
  71. [[SCCaptureInitializedState alloc] initWithPerformer:_queuePerformer
  72. bookKeeper:_bookKeeper
  73. delegate:self];
  74. [_states setObject:initializedState forKey:@(stateId)];
  75. }
  76. _currentState = [_states objectForKey:@(stateId)];
  77. break;
  78. case SCCaptureRunningStateId:
  79. if (![_states objectForKey:@(stateId)]) {
  80. SCCaptureRunningState *runningState =
  81. [[SCCaptureRunningState alloc] initWithPerformer:_queuePerformer bookKeeper:_bookKeeper delegate:self];
  82. [_states setObject:runningState forKey:@(stateId)];
  83. }
  84. _currentState = [_states objectForKey:@(stateId)];
  85. break;
  86. case SCCaptureImageStateId:
  87. if (![_states objectForKey:@(stateId)]) {
  88. SCCaptureImageState *captureImageState =
  89. [[SCCaptureImageState alloc] initWithPerformer:_queuePerformer bookKeeper:_bookKeeper delegate:self];
  90. [_states setObject:captureImageState forKey:@(stateId)];
  91. }
  92. _currentState = [_states objectForKey:@(stateId)];
  93. break;
  94. case SCCaptureImageWhileRecordingStateId:
  95. if (![_states objectForKey:@(stateId)]) {
  96. SCCaptureImageWhileRecordingState *captureImageWhileRecordingState =
  97. [[SCCaptureImageWhileRecordingState alloc] initWithPerformer:_queuePerformer
  98. bookKeeper:_bookKeeper
  99. delegate:self];
  100. [_states setObject:captureImageWhileRecordingState forKey:@(stateId)];
  101. }
  102. _currentState = [_states objectForKey:@(stateId)];
  103. break;
  104. case SCCaptureScanningStateId:
  105. if (![_states objectForKey:@(stateId)]) {
  106. SCCaptureScanningState *scanningState =
  107. [[SCCaptureScanningState alloc] initWithPerformer:_queuePerformer bookKeeper:_bookKeeper delegate:self];
  108. [_states setObject:scanningState forKey:@(stateId)];
  109. }
  110. _currentState = [_states objectForKey:@(stateId)];
  111. break;
  112. case SCCaptureRecordingStateId:
  113. if (![_states objectForKey:@(stateId)]) {
  114. SCCaptureRecordingState *recordingState = [[SCCaptureRecordingState alloc] initWithPerformer:_queuePerformer
  115. bookKeeper:_bookKeeper
  116. delegate:self];
  117. [_states setObject:recordingState forKey:@(stateId)];
  118. }
  119. _currentState = [_states objectForKey:@(stateId)];
  120. break;
  121. default:
  122. SCAssert(NO, @"illigal state Id");
  123. break;
  124. }
  125. [_currentState didBecomeCurrentState:payload resource:_captureResource context:context];
  126. }
  127. - (void)initializeCaptureWithDevicePositionAsynchronously:(SCManagedCaptureDevicePosition)devicePosition
  128. completionHandler:(dispatch_block_t)completionHandler
  129. context:(NSString *)context
  130. {
  131. [SCCaptureWorker setupCapturePreviewLayerController];
  132. SCTraceResumeToken resumeToken = SCTraceCapture();
  133. [_queuePerformer perform:^{
  134. SCTraceResume(resumeToken);
  135. [_currentState initializeCaptureWithDevicePosition:devicePosition
  136. resource:_captureResource
  137. completionHandler:completionHandler
  138. context:context];
  139. }];
  140. }
  141. - (SCCapturerToken *)startRunningWithContext:(NSString *)context completionHandler:(dispatch_block_t)completionHandler
  142. {
  143. [[SCLogger sharedInstance] updateLogTimedEventStart:kSCCameraMetricsOpen uniqueId:@""];
  144. SCCapturerToken *token = [[SCCapturerToken alloc] initWithIdentifier:context];
  145. SCTraceResumeToken resumeToken = SCTraceCapture();
  146. [_queuePerformer perform:^{
  147. SCTraceResume(resumeToken);
  148. [_currentState startRunningWithCapturerToken:token
  149. resource:_captureResource
  150. completionHandler:completionHandler
  151. context:context];
  152. }];
  153. return token;
  154. }
  155. - (void)stopRunningWithCapturerToken:(SCCapturerToken *)token
  156. completionHandler:(sc_managed_capturer_stop_running_completion_handler_t)completionHandler
  157. context:(NSString *)context
  158. {
  159. SCTraceResumeToken resumeToken = SCTraceCapture();
  160. [_queuePerformer perform:^{
  161. SCTraceResume(resumeToken);
  162. [_currentState stopRunningWithCapturerToken:token
  163. resource:_captureResource
  164. completionHandler:completionHandler
  165. context:context];
  166. }];
  167. }
  168. - (void)stopRunningWithCapturerToken:(SCCapturerToken *)token
  169. after:(NSTimeInterval)delay
  170. completionHandler:(sc_managed_capturer_stop_running_completion_handler_t)completionHandler
  171. context:(NSString *)context
  172. {
  173. SCTraceResumeToken resumeToken = SCTraceCapture();
  174. [_queuePerformer perform:^{
  175. SCTraceResume(resumeToken);
  176. [_currentState stopRunningWithCapturerToken:token
  177. resource:_captureResource
  178. completionHandler:completionHandler
  179. context:context];
  180. }
  181. after:delay];
  182. }
  183. - (void)prepareForRecordingAsynchronouslyWithAudioConfiguration:(SCAudioConfiguration *)configuration
  184. context:(NSString *)context
  185. {
  186. SCTraceResumeToken resumeToken = SCTraceCapture();
  187. [_queuePerformer perform:^{
  188. SCTraceResume(resumeToken);
  189. [_currentState prepareForRecordingWithResource:_captureResource
  190. audioConfiguration:configuration
  191. context:context];
  192. }];
  193. }
  194. - (void)startRecordingWithOutputSettings:(SCManagedVideoCapturerOutputSettings *)outputSettings
  195. audioConfiguration:(SCAudioConfiguration *)configuration
  196. maxDuration:(NSTimeInterval)maxDuration
  197. fileURL:(NSURL *)fileURL
  198. captureSessionID:(NSString *)captureSessionID
  199. completionHandler:(sc_managed_capturer_start_recording_completion_handler_t)completionHandler
  200. context:(NSString *)context
  201. {
  202. SCTraceResumeToken resumeToken = SCTraceCapture();
  203. [_queuePerformer perform:^{
  204. SCTraceResume(resumeToken);
  205. [_currentState startRecordingWithResource:_captureResource
  206. audioConfiguration:configuration
  207. outputSettings:outputSettings
  208. maxDuration:maxDuration
  209. fileURL:fileURL
  210. captureSessionID:captureSessionID
  211. completionHandler:completionHandler
  212. context:context];
  213. }];
  214. }
  215. - (void)stopRecordingWithContext:(NSString *)context
  216. {
  217. SCTraceResumeToken resumeToken = SCTraceCapture();
  218. [_queuePerformer perform:^{
  219. SCTraceResume(resumeToken);
  220. [_currentState stopRecordingWithResource:_captureResource context:context];
  221. }];
  222. }
  223. - (void)cancelRecordingWithContext:(NSString *)context
  224. {
  225. SCTraceResumeToken resumeToken = SCTraceCapture();
  226. [_queuePerformer perform:^{
  227. SCTraceResume(resumeToken);
  228. [_currentState cancelRecordingWithResource:_captureResource context:context];
  229. }];
  230. }
  231. - (void)captureStillImageAsynchronouslyWithAspectRatio:(CGFloat)aspectRatio
  232. captureSessionID:(NSString *)captureSessionID
  233. completionHandler:
  234. (sc_managed_capturer_capture_still_image_completion_handler_t)completionHandler
  235. context:(NSString *)context
  236. {
  237. [_queuePerformer perform:^() {
  238. [_currentState captureStillImageWithResource:_captureResource
  239. aspectRatio:aspectRatio
  240. captureSessionID:captureSessionID
  241. completionHandler:completionHandler
  242. context:context];
  243. }];
  244. }
  245. - (void)startScanAsynchronouslyWithScanConfiguration:(SCScanConfiguration *)configuration context:(NSString *)context
  246. {
  247. [_queuePerformer perform:^() {
  248. [_currentState startScanWithScanConfiguration:configuration resource:_captureResource context:context];
  249. }];
  250. }
  251. - (void)stopScanAsynchronouslyWithCompletionHandler:(dispatch_block_t)completionHandler context:(NSString *)context
  252. {
  253. [_queuePerformer perform:^() {
  254. [_currentState stopScanWithCompletionHandler:completionHandler resource:_captureResource context:context];
  255. }];
  256. }
  257. - (void)currentState:(SCCaptureBaseState *)state
  258. requestToTransferToNewState:(SCCaptureStateMachineStateId)newState
  259. payload:(SCStateTransitionPayload *)payload
  260. context:(NSString *)context
  261. {
  262. SCAssertPerformer(_queuePerformer);
  263. SCAssert(_currentState == state, @"state: %@ newState: %@ context:%@", SCCaptureStateName([state stateId]),
  264. SCCaptureStateName(newState), context);
  265. if (payload) {
  266. SCAssert(payload.fromState == [state stateId], @"From state id check");
  267. SCAssert(payload.toState == newState, @"To state id check");
  268. }
  269. if (_currentState != state) {
  270. return;
  271. }
  272. [_bookKeeper stateTransitionFrom:[state stateId] to:newState context:context];
  273. [self _setCurrentState:newState payload:payload context:context];
  274. }
  275. @end