Skip to content

Commit f5d25ba

Browse files
author
Vladislav Alekseev
committed
Add SimulatorVideoRecorder
1 parent 8671d77 commit f5d25ba

File tree

6 files changed

+115
-1
lines changed

6 files changed

+115
-1
lines changed

Package.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ let package = Package(
2626
.product(name: "Starscream", package: "Starscream"),
2727
.product(name: "SynchronousWaiter", package: "CommandLineToolkit"),
2828
"EmceePluginModels",
29+
"SimulatorVideoRecorder",
2930
]
3031
),
3132
.target(
3233
name: "EmceePluginModels"
33-
)
34+
),
35+
.target(
36+
name: "SimulatorVideoRecorder"
37+
),
3438
]
3539
)

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,8 @@ exit(try main())
5454
```
5555

5656
`Plugin` class will automatically stop streaming events when web socket gets disconnected, allowing `join()` method to return.
57+
58+
## Helpers
59+
60+
You can use `SimulatorVideoRecorder` to capture the video of the simulator.
61+
You should cancel all ongoing recording after you receive `didRun` event.

Sources/.DS_Store

-6 KB
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (c) Avito Tech LLC
3+
*/
4+
5+
import Foundation
6+
import PathLib
7+
8+
public protocol CancellableRecording {
9+
/// Stops recording and returns a path to a file where video is stored.
10+
func stopRecording() -> AbsolutePath
11+
12+
/// Cancels recording and does not write any data to the file. Thus, does not return any path.
13+
func cancelRecording()
14+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) Avito Tech LLC
3+
*/
4+
5+
import Foundation
6+
import PathLib
7+
import ProcessController
8+
9+
class CancellableRecordingImpl: CancellableRecording {
10+
private let outputPath: AbsolutePath
11+
private let recordingProcess: ProcessController
12+
13+
public init(
14+
outputPath: AbsolutePath,
15+
recordingProcess: ProcessController
16+
) {
17+
self.outputPath = outputPath
18+
self.recordingProcess = recordingProcess
19+
}
20+
21+
func stopRecording() -> AbsolutePath {
22+
recordingProcess.interruptAndForceKillIfNeeded {}
23+
recordingProcess.waitForProcessToDie()
24+
return outputPath
25+
}
26+
27+
func cancelRecording() {
28+
recordingProcess.terminateAndForceKillIfNeeded()
29+
recordingProcess.waitForProcessToDie()
30+
31+
let fileManager = FileManager()
32+
if fileManager.fileExists(atPath: outputPath.pathString) {
33+
try? fileManager.removeItem(atPath: outputPath.pathString)
34+
}
35+
}
36+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) Avito Tech LLC
3+
*/
4+
5+
import Foundation
6+
import PathLib
7+
import ProcessController
8+
9+
public final class SimulatorVideoRecorder {
10+
public enum CodecType: String {
11+
case h264
12+
case hevc
13+
}
14+
15+
private let processControllerProvider: ProcessControllerProvider
16+
private let simulatorUuid: String
17+
private let simulatorSetPath: AbsolutePath
18+
19+
public init(
20+
processControllerProvider: ProcessControllerProvider,
21+
simulatorUuid: String,
22+
simulatorSetPath: AbsolutePath
23+
) {
24+
self.processControllerProvider = processControllerProvider
25+
self.simulatorUuid = simulatorUuid
26+
self.simulatorSetPath = simulatorSetPath
27+
}
28+
29+
public func startRecording(
30+
codecType: CodecType,
31+
outputPath: AbsolutePath
32+
) throws -> CancellableRecording {
33+
let processController = try processControllerProvider.createProcessController(
34+
subprocess: Subprocess(
35+
arguments: [
36+
"/usr/bin/xcrun",
37+
"simctl",
38+
"--set",
39+
simulatorSetPath,
40+
"io",
41+
simulatorUuid,
42+
"recordVideo",
43+
"--codec=\(codecType.rawValue)",
44+
outputPath
45+
]
46+
)
47+
)
48+
try processController.start()
49+
50+
return CancellableRecordingImpl(
51+
outputPath: outputPath,
52+
recordingProcess: processController
53+
)
54+
}
55+
}

0 commit comments

Comments
 (0)