-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite with ScreenCaptureKit #80
base: main
Are you sure you want to change the base?
Conversation
Sources/Aperture/Aperture.swift
Outdated
@@ -1,228 +1,662 @@ | |||
import Foundation | |||
import AVFoundation | |||
import ScreenCaptureKit | |||
|
|||
public final class Aperture { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is simply a namespace, make it enum
instead.
Sources/Aperture/Aperture.swift
Outdated
public struct RecordingOptions { | ||
public init( | ||
destination: URL, | ||
targetId: String? = nil, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
targetId: String? = nil, | |
targetID: String? = nil, |
to match Swift style. Applies in other places too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! These are great. Took some courses on Swift before I wrote this to get a better understanding, but they don't really cover formatting
Is there something like eslint/prettier for Swift that can help me identify these? (and things like not adding : Bool
if there's a default value etc)
Using XCode fwiw, but I can use VSCode too if there's something available there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swiftlint
with this config: https://github.com/sindresorhus/swiftlint-config
Sources/Aperture/Aperture.swift
Outdated
case audioOnly | ||
} | ||
|
||
public enum ApertureError: Swift.Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public enum ApertureError: Swift.Error { | |
public enum Error: Swift.Error { |
Sources/Aperture/Aperture.swift
Outdated
case noTargetProvided | ||
case invalidFileExtension(String, Bool) | ||
case noDisplaysConnected | ||
case unknownError(Swift.Error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case unknownError(Swift.Error) | |
case unknown(Swift.Error) |
And should be last.
Sources/Aperture/Aperture.swift
Outdated
private var isRunning: Bool = false | ||
/// Whether the recorder is paused | ||
private var isPaused: Bool = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like these would be better as a single enum
. Maybe isStreamRecording
should also be included.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can I do this with an enum
? Do you mean struct
to hold each var? They can have independent values at times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can it be isRunning == true
and isPaused == true
at the same time?
Sources/Aperture/Aperture.swift
Outdated
externalDeviceCaptureSession.stopRunning() | ||
} | ||
|
||
if (assetWriter?.status == .writing) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (assetWriter?.status == .writing) { | |
if assetWriter?.status == .writing { |
Sources/Aperture/Aperture.swift
Outdated
audioDevice: audioDevice, | ||
videoCodec: videoCodec | ||
) | ||
extension Aperture.Recorder: SCStreamDelegate, SCStreamOutput, AVCaptureAudioDataOutputSampleBufferDelegate, AVCaptureVideoDataOutputSampleBufferDelegate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, one extension per conformance. Makes it easier to read.
Sources/Aperture/Aperture.swift
Outdated
private func initOutput(target: Aperture.Target, options: Aperture.RecordingOptions, streamConfig: SCStreamConfiguration) async throws { | ||
let assetWriter = try getAssetWriter(target: target, options: options) | ||
|
||
var audioSettings: [String: Any] = [AVSampleRateKey : 48000, AVNumberOfChannelsKey : 2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var audioSettings: [String: Any] = [AVSampleRateKey : 48000, AVNumberOfChannelsKey : 2] | |
var audioSettings: [String: Any] = [AVSampleRateKey: 48000, AVNumberOfChannelsKey: 2] |
case unknownError(Swift.Error) | ||
case noPermissions | ||
} | ||
public final class Recorder: NSObject { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Define this in an extension for improved readability.
Sources/Aperture/Aperture.swift
Outdated
|
||
/// Internal helpers for when we are resuming, used to fix the buffer timing | ||
private var isResuming: Bool = false | ||
private var timeOffset: CMTime = .zero |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private var timeOffset: CMTime = .zero | |
private var timeOffset = CMTime.zero |
Sources/Aperture/Utilities.swift
Outdated
|
||
service = IOIteratorNext(iterator) | ||
extension Aperture { | ||
public static func hasPermissions() async -> Bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static func hasPermissions() async -> Bool { | |
public static var hasPermissions: Bool { | |
get async { |
Sources/Aperture/Utilities.swift
Outdated
return "Unnamed screen" | ||
extension CMSampleBuffer { | ||
public func adjustTime(by offset: CMTime) -> CMSampleBuffer? { | ||
guard CMSampleBufferGetFormatDescription(self) != nil else { return nil } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use self.formatDescription
. Same with the other things.
@sindresorhus addressed all except for this and configured/ran swiftlint 😌 |
While working on
will be pushing a commit with those two at some point tomorrow |
Ok, I think it's ready:
|
Rewrites Aperture to use ScreenCaptureKit
Breaking changes:
highlightClicks
is only available on macOS 15+Aperture.Recorder()
and usestartRecording()
andstopRecording()
on itstartRecording
awaits until the file actually starts getting written before resolving, or throws any errors that happen during that timecropRect
is top/left now (this is howScreenCaptureKit
works by default)This has as much feature parity as possible (other then the
highlightClicks
note above) but it adds some functionality as well:.mov
and.m4v
for videos.m4a
for now, AAC or ALAC encoding)Potential features we'd want to add in a follow-up:
This PR still needs to update the readme, but wanted to get it reviewed first to fully land on the implementation before I go and update the readme
Closes #16
Closes #31
Closes #71
Closes #63
Closes #65
IssueHunt Summary
Referenced issues
This pull request has been submitted to: