Skip to content

Commit

Permalink
Add SimulatorVideoRecorder
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladislav Alekseev committed Feb 21, 2023
1 parent 8671d77 commit f5d25ba
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 1 deletion.
6 changes: 5 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ let package = Package(
.product(name: "Starscream", package: "Starscream"),
.product(name: "SynchronousWaiter", package: "CommandLineToolkit"),
"EmceePluginModels",
"SimulatorVideoRecorder",
]
),
.target(
name: "EmceePluginModels"
)
),
.target(
name: "SimulatorVideoRecorder"
),
]
)
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ exit(try main())
```

`Plugin` class will automatically stop streaming events when web socket gets disconnected, allowing `join()` method to return.

## Helpers

You can use `SimulatorVideoRecorder` to capture the video of the simulator.
You should cancel all ongoing recording after you receive `didRun` event.
Binary file removed Sources/.DS_Store
Binary file not shown.
14 changes: 14 additions & 0 deletions Sources/SimulatorVideoRecorder/CancellableRecording.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) Avito Tech LLC
*/

import Foundation
import PathLib

public protocol CancellableRecording {
/// Stops recording and returns a path to a file where video is stored.
func stopRecording() -> AbsolutePath

/// Cancels recording and does not write any data to the file. Thus, does not return any path.
func cancelRecording()
}
36 changes: 36 additions & 0 deletions Sources/SimulatorVideoRecorder/CancellableRecordingImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) Avito Tech LLC
*/

import Foundation
import PathLib
import ProcessController

class CancellableRecordingImpl: CancellableRecording {
private let outputPath: AbsolutePath
private let recordingProcess: ProcessController

public init(
outputPath: AbsolutePath,
recordingProcess: ProcessController
) {
self.outputPath = outputPath
self.recordingProcess = recordingProcess
}

func stopRecording() -> AbsolutePath {
recordingProcess.interruptAndForceKillIfNeeded {}
recordingProcess.waitForProcessToDie()
return outputPath
}

func cancelRecording() {
recordingProcess.terminateAndForceKillIfNeeded()
recordingProcess.waitForProcessToDie()

let fileManager = FileManager()
if fileManager.fileExists(atPath: outputPath.pathString) {
try? fileManager.removeItem(atPath: outputPath.pathString)
}
}
}
55 changes: 55 additions & 0 deletions Sources/SimulatorVideoRecorder/SimulatorVideoRecorder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) Avito Tech LLC
*/

import Foundation
import PathLib
import ProcessController

public final class SimulatorVideoRecorder {
public enum CodecType: String {
case h264
case hevc
}

private let processControllerProvider: ProcessControllerProvider
private let simulatorUuid: String
private let simulatorSetPath: AbsolutePath

public init(
processControllerProvider: ProcessControllerProvider,
simulatorUuid: String,
simulatorSetPath: AbsolutePath
) {
self.processControllerProvider = processControllerProvider
self.simulatorUuid = simulatorUuid
self.simulatorSetPath = simulatorSetPath
}

public func startRecording(
codecType: CodecType,
outputPath: AbsolutePath
) throws -> CancellableRecording {
let processController = try processControllerProvider.createProcessController(
subprocess: Subprocess(
arguments: [
"/usr/bin/xcrun",
"simctl",
"--set",
simulatorSetPath,
"io",
simulatorUuid,
"recordVideo",
"--codec=\(codecType.rawValue)",
outputPath
]
)
)
try processController.start()

return CancellableRecordingImpl(
outputPath: outputPath,
recordingProcess: processController
)
}
}

0 comments on commit f5d25ba

Please sign in to comment.